Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 23 additions & 102 deletions doc/ovhcloud.md
Original file line number Diff line number Diff line change
@@ -1,90 +1,36 @@
# OVHcloud CLI (`ovhcloud`) Documentation
## ovhcloud

---
CLI to manage your OVHcloud services

## Overview
### Options

`ovhcloud` is a single, unified command‑line interface for managing the full range of OVHcloud products and account resources directly from your terminal. Whether you need to automate provisioning, perform quick look‑ups, or integrate OVHcloud operations into CI/CD pipelines, `ovhcloud` offers fine‑grained commands and consistent output formats (table, JSON, YAML, or custom gval expressions).

---

## Quick Start

```bash
# Display the top‑level help
ovhcloud --help

# Log in and create API credentials (interactive)
ovhcloud login

# List your VPS instances as JSON
ohvcloud vps list -o json
```

Check out the [authentication page](authentication.md) for further information about the authentication means.

You can manage multiple OVHcloud accounts using [profiles](profiles.md). Create a profile with `ovhcloud login --profile <name>`, switch between them with `ovhcloud config profile switch <name>`, or use `--profile <name>` on any command.

### Generate Shell Completion

```bash
# Bash
eval "$(./ovhcloud completion bash)"
# Zsh
eval "$(./ovhcloud completion zsh)"
# Fish
./ovhcloud completion fish | source
# PowerShell
./ovhcloud completion powershell | Out-String | Invoke-Expression
```

Add the appropriate line to your shell’s startup file (`~/.bashrc`, `~/.zshrc`, etc.) to enable persistent autocompletion.

---

## Global Usage

```text
ovhcloud [command] [flags]
-d, --debug Activate debug mode (will log all HTTP requests details)
-h, --help help for ovhcloud
-e, --ignore-errors Ignore errors in API calls when it is not fatal to the execution
-o, --output string Output format: json, yaml, interactive, or a custom format expression (using https://github.com/PaesslerAG/gval syntax)
Examples:
--output json
--output yaml
--output interactive
--output 'id' (to extract a single field)
--output 'nested.field.subfield' (to extract a nested field)
--output '[id, "name"]' (to extract multiple fields as an array)
--output '{"newKey": oldKey, "otherKey": nested.field}' (to extract and rename fields in an object)
--output 'name+","+type' (to extract and concatenate fields in a string)
--output '(nbFieldA + nbFieldB) * 10' (to compute values from numeric fields)
--profile string Use a specific profile from the configuration file
```

### Global Flags

| Flag | Description |
| ------------------ | ---------------------------------------------------- |
| `--debug` | Activate debug mode (logs all HTTP‑request details). |
| `--ignore-errors` | Ignore errors of API calls made when listing items. |
| `--filter <expr>` | Filter lists output with a [gval] expression. |
| `-h`, `--help` | Display help for `ovhcloud` or a specific command. |
| `-o interactive` | Produce interactive (prompt‑based) output. |
| `-o json` | Output data in JSON format. |
| `-o yaml` | Output data in YAML format. |
| `-o <expr>` | Format output with a [gval] expression. |

[gval]: https://github.com/PaesslerAG/gval

#### Filtering examples

- Strict string equality: `--filter 'name=="something"'`
- String regexp comparison: `--filter 'name=~"something"'`
- Number comparison: `--filter 'bootId > 1'`

#### Formatting example

- Extract only one field: `-o 'ip'`
- Extract an object: `-o '{name: ip}'`

---

## Command Reference

Below is the full list of primary sub‑commands available at the time of writing. Each can be explored in depth with `ovhcloud <command> --help`.
### SEE ALSO

* [ovhcloud account](ovhcloud_account.md) - Manage your account
* [ovhcloud alldom](ovhcloud_alldom.md) - Retrieve information and manage your AllDom services
* [ovhcloud baremetal](ovhcloud_baremetal.md) - Retrieve information and manage your Bare Metal services
* [ovhcloud browser](ovhcloud_browser.md) - Launch a TUI for the OVHcloud Manager - Public Cloud universe only [EXPERIMENTAL]
* [ovhcloud cdn-dedicated](ovhcloud_cdn-dedicated.md) - Retrieve information and manage your dedicated CDN services
* [ovhcloud cloud](ovhcloud_cloud.md) - Manage your projects and services in the Public Cloud universe (MKS, MPR, MRS, Object Storage...)
* [ovhcloud completion](ovhcloud_completion.md) - Generate shell completion scripts
* [ovhcloud config](ovhcloud_config.md) - Manage your CLI configuration
* [ovhcloud dedicated-ceph](ovhcloud_dedicated-ceph.md) - Retrieve information and manage your Dedicated Ceph services
* [ovhcloud dedicated-cloud](ovhcloud_dedicated-cloud.md) - Retrieve information and manage your DedicatedCloud services
Expand All @@ -102,6 +48,7 @@ Below is the full list of primary sub‑commands available at the time of writin
* [ovhcloud ldp](ovhcloud_ldp.md) - Retrieve information and manage your LDP (Logs Data Platform) services
* [ovhcloud location](ovhcloud_location.md) - Retrieve information and manage your Location services
* [ovhcloud login](ovhcloud_login.md) - Login to your OVHcloud account to create API credentials
* [ovhcloud logout](ovhcloud_logout.md) - Revoke your API credentials and remove them from the configuration
* [ovhcloud nutanix](ovhcloud_nutanix.md) - Retrieve information and manage your Nutanix services
* [ovhcloud okms](ovhcloud_okms.md) - Retrieve information and manage your OKMS (Key Management Services)
* [ovhcloud overthebox](ovhcloud_overthebox.md) - Retrieve information and manage your OverTheBox services
Expand All @@ -113,6 +60,7 @@ Below is the full list of primary sub‑commands available at the time of writin
* [ovhcloud storage-netapp](ovhcloud_storage-netapp.md) - Retrieve information and manage your Storage NetApp services
* [ovhcloud support-tickets](ovhcloud_support-tickets.md) - Retrieve information and manage your support tickets
* [ovhcloud telephony](ovhcloud_telephony.md) - Retrieve information and manage your Telephony services
* [ovhcloud upgrade](ovhcloud_upgrade.md) - Upgrade OVHcloud CLI to the latest version
* [ovhcloud veeamcloudconnect](ovhcloud_veeamcloudconnect.md) - Retrieve information and manage your VeeamCloudConnect services
* [ovhcloud veeamenterprise](ovhcloud_veeamenterprise.md) - Retrieve information and manage your VeeamEnterprise services
* [ovhcloud version](ovhcloud_version.md) - Get OVHcloud CLI version
Expand All @@ -124,30 +72,3 @@ Below is the full list of primary sub‑commands available at the time of writin
* [ovhcloud webhosting](ovhcloud_webhosting.md) - Retrieve information and manage your WebHosting services
* [ovhcloud xdsl](ovhcloud_xdsl.md) - Retrieve information and manage your XDSL services

> **Tip**  Use `-o json`, `-o yaml`, or `-o <format>` with a gval expression to integrate `ovhcloud` into scripts and automation pipelines.

---

## Examples

| Task | Command |
| ------------------------------------- | ---------------------------------------------- |
| Log in and save credentials | `ovhcloud login` |
| List VPS instances (tabular) | `ovhcloud vps list` |
| Fetch details of a single VPS in JSON | `ovhcloud vps get <service_id> -o json` |
| Reinstall a baremetal interactively | `ovhcloud baremetal reinstall <id> --editor` |

---

## Troubleshooting

* **Verbose output** — Use `--debug` to inspect raw API calls and responses.
* **Authentication issues** — Run `ovhcloud login` again to regenerate valid API keys.
* **Rate limits** — OVHcloud APIs impose rate limits; plan retries or exponential backoff in scripts.

---

## Further Reading

* OVHcloud API reference: [https://eu.api.ovh.com/console](https://eu.api.ovh.com/console)
* OVHcloud community guides and tutorials.
1 change: 1 addition & 0 deletions doc/ovhcloud_baremetal.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Retrieve information and manage your Bare Metal services
* [ovhcloud baremetal confirm-termination](ovhcloud_baremetal_confirm-termination.md) - Confirm the termination of the given baremetal
* [ovhcloud baremetal edit](ovhcloud_baremetal_edit.md) - Update the given baremetal
* [ovhcloud baremetal get](ovhcloud_baremetal_get.md) - Retrieve information of a specific baremetal
* [ovhcloud baremetal install-status](ovhcloud_baremetal_install-status.md) - Show how far the running installation of this baremetal has got
* [ovhcloud baremetal ipmi](ovhcloud_baremetal_ipmi.md) - Manage IPMI on your baremetal
* [ovhcloud baremetal list](ovhcloud_baremetal_list.md) - List your Baremetal services
* [ovhcloud baremetal list-compatible-os](ovhcloud_baremetal_list-compatible-os.md) - Retrieve OSes that can be installed on this baremetal
Expand Down
37 changes: 37 additions & 0 deletions doc/ovhcloud_baremetal_install-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## ovhcloud baremetal install-status

Show how far the running installation of this baremetal has got

```
ovhcloud baremetal install-status <service_name> [flags]
```

### Options

```
-h, --help help for install-status
```

### Options inherited from parent commands

```
-d, --debug Activate debug mode (will log all HTTP requests details)
-e, --ignore-errors Ignore errors in API calls when it is not fatal to the execution
-o, --output string Output format: json, yaml, interactive, or a custom format expression (using https://github.com/PaesslerAG/gval syntax)
Examples:
--output json
--output yaml
--output interactive
--output 'id' (to extract a single field)
--output 'nested.field.subfield' (to extract a nested field)
--output '[id, "name"]' (to extract multiple fields as an array)
--output '{"newKey": oldKey, "otherKey": nested.field}' (to extract and rename fields in an object)
--output 'name+","+type' (to extract and concatenate fields in a string)
--output '(nbFieldA + nbFieldB) * 10' (to compute values from numeric fields)
--profile string Use a specific profile from the configuration file
```

### SEE ALSO

* [ovhcloud baremetal](ovhcloud_baremetal.md) - Retrieve information and manage your Bare Metal services

46 changes: 46 additions & 0 deletions doc/ovhcloud_logout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## ovhcloud logout

Revoke your API credentials and remove them from the configuration

```
ovhcloud logout [flags]
```

### Examples

```
ovhcloud logout
ovhcloud logout --yes
ovhcloud logout --profile work
```

### Options

```
-h, --help help for logout
-y, --yes Do not ask for confirmation
```

### Options inherited from parent commands

```
-d, --debug Activate debug mode (will log all HTTP requests details)
-e, --ignore-errors Ignore errors in API calls when it is not fatal to the execution
-o, --output string Output format: json, yaml, interactive, or a custom format expression (using https://github.com/PaesslerAG/gval syntax)
Examples:
--output json
--output yaml
--output interactive
--output 'id' (to extract a single field)
--output 'nested.field.subfield' (to extract a nested field)
--output '[id, "name"]' (to extract multiple fields as an array)
--output '{"newKey": oldKey, "otherKey": nested.field}' (to extract and rename fields in an object)
--output 'name+","+type' (to extract and concatenate fields in a string)
--output '(nbFieldA + nbFieldB) * 10' (to compute values from numeric fields)
--profile string Use a specific profile from the configuration file
```

### SEE ALSO

* [ovhcloud](ovhcloud.md) - CLI to manage your OVHcloud services

15 changes: 13 additions & 2 deletions internal/cmd/baremetal.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/ovh/ovhcloud-cli/internal/completion"
"github.com/ovh/ovhcloud-cli/internal/flags"
"github.com/ovh/ovhcloud-cli/internal/services/baremetal"
"github.com/ovh/ovhcloud-cli/internal/services/common"
"github.com/ovh/ovhcloud-cli/internal/services/vrack"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -124,7 +123,7 @@ they are not sold from the public price list, and show as "on quotation".`,
ValidArgsFunction: completion.ServiceList("/v1/dedicated/server"),
Run: baremetal.EditBaremetalServiceInfo,
}
common.AddServiceInfoRenewFlags(baremetalServiceInfoEditCmd)
addServiceInfoRenewFlags(baremetalServiceInfoEditCmd)
addInteractiveEditorFlag(baremetalServiceInfoEditCmd)
baremetalServiceInfoCmd.AddCommand(baremetalServiceInfoEditCmd)

Expand Down Expand Up @@ -419,6 +418,18 @@ a server is sitting on the power-off entry.`,
Run: baremetal.GetBaremetalRaidProfile,
}))

// A reinstall runs for tens of minutes and, until now, said nothing while
// it did. This reads the same progress `reinstall --wait` follows, for
// somebody who started the install in another terminal — or who answered
// the confirmation, walked away, and wants to know whether to keep waiting.
baremetalCmd.AddCommand(&cobra.Command{
Use: "install-status <service_name>",
Short: "Show how far the running installation of this baremetal has got",
Args: cobra.ExactArgs(1),
ValidArgsFunction: completion.ServiceList("/v1/dedicated/server"),
Run: baremetal.ShowBaremetalInstallStatus,
})

// Commands to manage virtual network interfaces
// Private network, seen from the machine. The same work lives under
// `ovhcloud vrack`; this is where somebody holding a server looks for it.
Expand Down
71 changes: 71 additions & 0 deletions internal/cmd/baremetal_install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,77 @@ func (ms *MockSuite) TestBaremetalRaidProfileListsControllersAndDisks(assert, re
assert.Cmp(out, td.Contains("3726GiB"))
}

// Outside an installation the route answers 404 with a sentence, not a
// payload. That is the state most servers are in most of the time, and it is
// an answer: reporting it as a failure would send somebody looking for a
// broken command.
func (ms *MockSuite) TestBaremetalInstallStatusTreatsIdleAsAnAnswer(assert, require *td.T) {
httpmock.RegisterResponder("GET",
"https://eu.api.ovh.com/v1/dedicated/server/fakeBaremetal/install/status",
httpmock.NewStringResponder(404,
`{"message": "Server is not being installed or reinstalled at the moment"}`))

out, err := cmd.Execute("baremetal", "install-status", "fakeBaremetal")

require.CmpNoError(err, "an idle server is not a failed command")
assert.Cmp(out, td.Contains("not being installed"))
}

// A genuine failure stays one: the message match only ever softens the idle
// case.
func (ms *MockSuite) TestBaremetalInstallStatusStillReportsRealFailures(assert, require *td.T) {
httpmock.RegisterResponder("GET",
"https://eu.api.ovh.com/v1/dedicated/server/fakeBaremetal/install/status",
httpmock.NewStringResponder(403, `{"message": "This call has not been granted"}`))

_, err := cmd.Execute("baremetal", "install-status", "fakeBaremetal")

require.CmpError(err)
assert.Cmp(err.Error(), td.Contains("not been granted"))
}

// The point of the command is to say which step is running and for how long.
// A list of steps without either is the same non-answer --wait used to give.
func (ms *MockSuite) TestBaremetalInstallStatusNamesTheRunningStep(assert, require *td.T) {
httpmock.RegisterResponder("GET",
"https://eu.api.ovh.com/v1/dedicated/server/fakeBaremetal/install/status",
httpmock.NewStringResponder(200, `{
"elapsedTime": 754,
"progress": [
{"comment": "Initialising Installation process", "status": "done"},
{"comment": "Installing operating system", "status": "doing"},
{"comment": "Rebooting", "status": "todo"}
]
}`))

out, err := cmd.Execute("baremetal", "install-status", "fakeBaremetal")

require.CmpNoError(err)
assert.Cmp(out, td.Contains("step 2 of 3"), "the position has to be visible")
assert.Cmp(out, td.Contains("Installing operating system"))
assert.Cmp(out, td.Contains("12m34s"), "754 seconds, not 754")
assert.Cmp(out, td.Contains("API reports"),
"the figure is the API's: measured shifting origin mid-install")
assert.Cmp(out, td.Contains("Rebooting"), "and the steps still to come")
}

// The error of a failed step is what says why, so it travels with it.
func (ms *MockSuite) TestBaremetalInstallStatusShowsWhyAStepFailed(assert, require *td.T) {
httpmock.RegisterResponder("GET",
"https://eu.api.ovh.com/v1/dedicated/server/fakeBaremetal/install/status",
httpmock.NewStringResponder(200, `{
"elapsedTime": 42,
"progress": [
{"comment": "Partitioning", "status": "error", "error": "disk 2 is not present"}
]
}`))

out, err := cmd.Execute("baremetal", "install-status", "fakeBaremetal")

require.CmpNoError(err)
assert.Cmp(out, td.Contains("disk 2 is not present"))
}

// --filter is registered on both commands, so it has to do something. A test
// that only checks the kept row would pass just as well with the filtering
// removed, which is why the assertion that matters is the absence of the other
Expand Down
Loading
Loading