diff --git a/website/content/docs/boxes/format.mdx b/website/content/docs/boxes/format.mdx index d51285995..bd8d4e329 100644 --- a/website/content/docs/boxes/format.mdx +++ b/website/content/docs/boxes/format.mdx @@ -60,5 +60,7 @@ because it cannot verify the provider. Other keys/values may be added to the metadata without issue. The value of the metadata file is passed opaquely into Vagrant and plugins can make -use of it. At this point, Vagrant core does not use any other keys in this -file. +use of it. Values currently used by Vagrant core: + +* `provider` - (string) Provider for the box +* `architecture` - (string) Architecture of the box diff --git a/website/content/docs/vagrantfile/machine_settings.mdx b/website/content/docs/vagrantfile/machine_settings.mdx index 62e312b1f..430979806 100644 --- a/website/content/docs/vagrantfile/machine_settings.mdx +++ b/website/content/docs/vagrantfile/machine_settings.mdx @@ -43,7 +43,7 @@ the name of the synced folder plugin. [HashiCorp's Vagrant Cloud](/vagrant/vagrant-cloud). - `config.vm.box_architecture` (string) - The architecture of the box to be used. - Supported architecture values: "386", "amd64", "arm", "arm64", "ppc64le", "ppc64", + Supported architecture values: "i386", "amd64", "arm", "arm64", "ppc64le", "ppc64", "mips64le", "mips64", "mipsle", "mips", and "s390x". The special value `:auto` will detect the host architecture and fetch the appropriate box, if available. When the value is set to `nil`, it will fetch the box flagged as the default architecture. diff --git a/website/content/vagrant-cloud/api.mdx b/website/content/vagrant-cloud/api/v1.mdx similarity index 99% rename from website/content/vagrant-cloud/api.mdx rename to website/content/vagrant-cloud/api/v1.mdx index 0fb5d5b38..d7d22018e 100644 --- a/website/content/vagrant-cloud/api.mdx +++ b/website/content/vagrant-cloud/api/v1.mdx @@ -1,10 +1,10 @@ --- layout: vagrant-cloud -page_title: Vagrant Cloud API +page_title: Vagrant Cloud API (Version 1) description: "Vagrant Cloud provides an API for users to interact with Vagrant Cloud for experimentation, automation, or building new features and tools on top of our existing application." --- -# Vagrant Cloud API +# Vagrant Cloud API (Version 1) ## Using the API @@ -18,7 +18,7 @@ Clients can authenticate using an authentication token. The token can be passed to Vagrant Cloud one of two ways: 1. (Preferred) Set the `Authorization` header to `"Bearer "` and the value of the authentication token. -2. Pass the authentication token as an `access_token` URL parameter. +2. Pass the authentication token as an `access_token` URL parameter (_NOTE_: deprecated). Examples below will set the header, but feel free to use whichever method is easier for your implementation. diff --git a/website/content/vagrant-cloud/api/v2.mdx b/website/content/vagrant-cloud/api/v2.mdx new file mode 100644 index 000000000..b73b14d06 --- /dev/null +++ b/website/content/vagrant-cloud/api/v2.mdx @@ -0,0 +1,1437 @@ +--- +layout: vagrant-cloud +page_title: Vagrant Cloud API (Version 2) +description: "Vagrant Cloud provides an API for users to interact with Vagrant Cloud for experimentation, automation, or building new features and tools on top of our existing application." +--- + +# Vagrant Cloud API (Version 2) + +## Using the API + +Vagrant Cloud provides an API for users to interact with Vagrant Cloud for experimentation, automation, or building new features and tools on top of our existing application. + +### Authentication + +Some API endpoints require authentication to create new resources, update or delete existing resources, or to read a private resource. + +Clients can authenticate using an authentication token. +The token can be passed to Vagrant Cloud one of two ways: + +1. (Preferred) Set the `Authorization` header to `"Bearer "` and the value of the authentication token. +2. Pass the authentication token as an `access_token` URL parameter (_NOTE_: deprecated). + +Examples below will set the header, but feel free to use whichever method is easier for your implementation. + +-> The `X-Atlas-Token` header is also supported for backwards-compatibility. + +### Request and Response Format + +Requests to Vagrant Cloud which include data attributes (`POST` or `PUT`/`PATCH`) should set the `Content-Type` header to `"application/json"`, and include a valid JSON body with the request. + +JSON responses may include an `errors` key, which will contain an array of error strings, as well as a `success` key. +For example: + +```json +{ + "errors": ["Resource not found!"], + "success": false +} +``` + +### Response Codes + +Vagrant Cloud may respond with the following response codes, depending on the status of the request and context: + +#### Success + +##### **200** OK + +##### **201** Created + +##### **204** No Content + +#### Client Errors + +##### **401** Unauthorized + +You do not have authorization to access the requested resource. + +##### **402** Payment Required + +You are trying to access a resource which is delinquent on billing. +Please contact the owner of the resource so that they can update their billing information. + +##### **403** Forbidden + +You are attempting to use the system in a way which is not allowed. +There could be required request parameters that are missing, or one of the parameters is invalid. +Please check the response `errors` key, and double-check the examples below for any discrepancies. + +##### **404** Not Found + +The resource you are trying to access does not exist. This may also be returned if you attempt to access a private resource that you don't have authorization to view. + +##### **422** Unprocessable Entity + +##### **429** Too Many Requests + +You are currently being rate-limited. Please decrease your frequency of usage, or contact us at [support+vagrantcloud@hashicorp.com](mailto:support+vagrantcloud@hashicorp.com) with a description of your use case so that we can consider creating an exception. + +#### Server Errors + +##### **500** Internal Server Error + +The server failed to respond to the request for an unknown reason. +Please contact [support+vagrantcloud@hashicorp.com](mailto:support+vagrantcloud@hashicorp.com) with a description of the problem so that we can investigate. + +##### **503** Service Unavailable + +Vagrant Cloud is temporarily in maintenance mode. +Please check the [HashiCorp Status Site](http://status.hashicorp.com) for more information. + +## Creating a usable box from scratch + +-> This assumes that you have a valid Vagrant Cloud authentication token. You can [create one via the API](#create-a-token), or [create one on the Vagrant Cloud website](https://app.vagrantup.com/settings/security). + +In order to create a usable box on Vagrant Cloud, perform the following steps: + +1. [Create a new box](#create-a-box) +1. [Create a new version](#create-a-version) +1. [Create a new provider](#create-a-provider) +1. [Upload a box image for that provider](#upload-a-provider) +1. [Release the version](#release-a-version) + +#### Example Requests + + + + +```shell +# Create a new box +curl \ + --request POST \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/boxes \ + --data '{ "box": { "username": "myuser", "name": "test" } }' + +# Create a new version + +curl \ + --request POST \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/versions \ + --data '{ "version": { "version": "1.2.3" } }' + +# Create a new provider + +curl \ + --request POST \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/providers \ + --data '{ "provider": { "name": "virtualbox" } }' + +# Prepare the provider for upload/get an upload URL + +response=$(curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/upload) + +# Extract the upload URL from the response (requires the jq command) + +upload_path=$(echo "$response" | jq .upload_path) + +# Perform the upload + +curl --request PUT "${upload_path}" --upload-file virtualbox-1.2.3.box + +# Release the version + +curl \ + --request PUT \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/release + +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Content-Type" => "application/json", + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +# Create a new box + +api.post "/api/v2/boxes", +json: { box: { username: "myuser", name: "test" } } + +# Create a new version + +api.post "/api/v2/box/myuser/test/versions", +json: { version: { version: "1.2.3" } } + +# Create a new provider + +api.post "/api/v2/box/myuser/test/version/1.2.3/providers", +json: { provider: { name: "virtualbox" } } + +# Prepare the provider for upload + +response = api.get("/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/upload") + +# Extract the upload URL + +upload_path = response.parse['upload_path'] + +# Upload the box image + +HTTP.put upload_path, body: File.open("virtualbox-1.2.3.box") + +# Release the version + +api.put("/api/v2/box/myuser/test/version/1.2.3/release") +``` + + + + +## Authentication + +### Validate a token + +`GET /api/v2/authenticate` + +Responds [`200 OK`](#200-ok) if the authentication request was successful, otherwise responds [`401 Unauthorized`](#401-unauthorized). + +#### Example Request + + + + +```shell +curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/authenticate +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/authenticate") + +if response.status.success? # Success, the response attributes are available here. + p response.parse +else # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +## Organizations + +### Read an organization + +`GET /api/v2/user/:username` + +#### Example Request + + + + +```shell +curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/user/myuser +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/user/myuser") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +```json +{ + "username": "myuser", + "avatar_url": "https://www.gravatar.com/avatar/130a640278870c3dada38b3d912ee022?s=460&d=mm", + "profile_html": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

\n", + "profile_markdown": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + "boxes": [] +} +``` + +## Search + +### Search for boxes + +`GET /api/v2/search` + +#### Arguments + +- `q` - (Optional) The search query. Results will match the `username`, `name`, or `short_description` fields for a box. If omitted, the top boxes based on `sort` and `order` will be returned (defaults to "downloads desc"). +- `architcture` (Optional) Filter results to boxes supporting a specific architecture. +- `provider` - (Optional) Filter results to boxes supporting for a specific provider. +- `sort` - (Optional, default: `"downloads"`) The field to sort results on. Can be one of `"downloads"`, `"created"`, or `"updated"`. +- `order` - (Optional, default: `"desc"`) The order to return the sorted field in. Can be `"desc"` os `"asc"`. +- `limit` - (Optional, default: `10`) The number of results to return (max of 100). +- `page` - (Optional, default: `1`) + +#### Example Request + + + + +```shell +curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + "https://app.vagrantup.com/api/v2/search?q=test&provider=virtualbox" +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/search", params: { + q: "test", + provider: "virtualbox" +}) + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +```json +{ + "boxes": [ + { + "created_at": "2017-10-20T14:19:59.842Z", + "updated_at": "2017-10-20T15:23:53.363Z", + "tag": "myuser/test", + "name": "test", + "short_description": "My dev box", + "description_html": "

My development Vagrant box

\n", + "username": "myuser", + "description_markdown": "My development Vagrant box", + "private": true, + "downloads": 123, + "current_version": { + "version": "1.2.3", + "status": "active", + "description_html": "

A new version

\n", + "description_markdown": "A new version", + "created_at": "2017-10-20T15:23:17.184Z", + "updated_at": "2017-10-20T15:23:53.355Z", + "number": "1.2.3", + "release_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/release", + "revoke_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/revoke", + "providers": [ + { + "name": "virtualbox", + "hosted": false, + "hosted_token": null, + "original_url": "https://example.com/virtualbox-1.2.3.box", + "created_at": "2017-10-20T15:23:35.718Z", + "updated_at": "2017-10-20T15:23:35.718Z", + "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box" + } + ] + } + } + ] +} +``` + +## Boxes + +### Read a box + +`GET /api/v2/box/:username/:name` + +#### Example Request + + + + +```shell +curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/box/myuser/test") + +if response.status.success? # Success, the response attributes are available here. + p response.parse +else # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +```json +{ + "created_at": "2017-10-20T14:19:59.842Z", + "updated_at": "2017-10-20T15:23:53.363Z", + "tag": "myuser/test", + "name": "test", + "short_description": "My dev box", + "description_html": "

My development Vagrant box

\n", + "username": "myuser", + "description_markdown": "My development Vagrant box", + "private": true, + "downloads": 123, + "current_version": { + "version": "1.2.3", + "status": "active", + "description_html": "

A new version

\n", + "description_markdown": "A new version", + "created_at": "2017-10-20T15:23:17.184Z", + "updated_at": "2017-10-20T15:23:53.355Z", + "number": "1.2.3", + "release_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/release", + "revoke_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/revoke", + "providers": [ + { + "name": "virtualbox", + "hosted": false, + "hosted_token": null, + "original_url": "https://example.com/virtualbox-1.2.3.box", + "created_at": "2017-10-20T15:23:35.718Z", + "updated_at": "2017-10-20T15:23:35.718Z", + "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box" + } + ] + }, + "versions": [ + { + "version": "1.2.3", + "status": "active", + "description_html": "

A new version

\n", + "description_markdown": "A new version", + "created_at": "2017-10-20T15:23:17.184Z", + "updated_at": "2017-10-20T15:23:53.355Z", + "number": "1.2.3", + "release_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/release", + "revoke_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/revoke", + "providers": [ + { + "name": "virtualbox", + "hosted": false, + "hosted_token": null, + "original_url": "https://example.com/virtualbox-1.2.3.box", + "created_at": "2017-10-20T15:23:35.718Z", + "updated_at": "2017-10-20T15:23:35.718Z", + "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box" + } + ] + } + ] +} +``` + +### Create a box + +`POST /api/v2/boxes` + +#### Arguments + +- `box` + - `username` - The username of the organization that will own this box. + - `name` - The name of the box. + - `short_description` - A short summary of the box. + - `description` - A longer description of the box. Can be formatted with [Markdown][markdown]. + - `is_private` (Optional, default: `true`) - Whether or not this box is private. + +#### Example Request + + + + +```shell +curl \ + --request POST \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/boxes \ + --data ' + { + "box": { + "username": "myuser", + "name": "test", + "short_description": "My dev box", + "description": "My development Vagrant box", + "is_private": true + } + } + ' +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Content-Type" => "application/json", + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.post("/api/v2/boxes", json: { + box: { + username: "myuser", + name: "test", + short_description: "My dev box", + description: "My development Vagrant box", + is_private: true + } +}) + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a box](#read-a-box). + +### Update a box + +`PUT /api/v2/box/:username/:name` + +#### Arguments + +- `box` + - `name` - The name of the box. + - `short_description` - A short summary of the box. + - `description` - A longer description of the box. Can be formatted with [Markdown](https://daringfireball.net/projects/markdown/syntax). + - `is_private` (Optional, default: `true`) - Whether or not this box is private. + +#### Example Request + + + + +```shell +curl \ + --request PUT \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test \ + --data ' + { + "box": { + "name": "test", + "short_description": "My dev box", + "description": "My development Vagrant box", + "is_private": true + } + } + ' +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Content-Type" => "application/json", + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.put("/api/v2/box/myuser/test", json: { + box: { + name: "test", + short_description: "My dev box", + description: "My development Vagrant box", + is_private: true + } +}) + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +### Delete a box + +`DELETE /api/v2/box/:username/:name` + +#### Example Request + + + + +```shell +curl \ + --request DELETE \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.delete("/api/v2/box/myuser/test") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a box](#read-a-box). + +## Versions + +### Read a version + +`GET /api/v2/box/:username/:name/version/:version` + +#### Example Request + + + + +```shell +curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3 +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/box/myuser/test/version/1.2.3") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +```json +{ + "version": "1.2.3", + "status": "active", + "description_html": "

A new version

\n", + "description_markdown": "A new version", + "created_at": "2017-10-20T15:23:17.184Z", + "updated_at": "2017-10-20T15:23:53.355Z", + "number": "1.2.3", + "release_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/release", + "revoke_url": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/revoke", + "providers": [ + { + "name": "virtualbox", + "hosted": false, + "hosted_token": null, + "original_url": "https://example.com/virtualbox-1.2.3.box", + "created_at": "2017-10-20T15:23:35.718Z", + "updated_at": "2017-10-20T15:23:35.718Z", + "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box", + "architecture": "amd64", + "default_architecture": true + } + ] +} +``` + +### Create a version + +`POST /api/v2/box/:username/:name/versions` + +-> New versions start as `unreleased`. You must create a valid provider before releasing a new version. + +#### Arguments + +- `version` + - `version` - The version number of this version. + - `description` - A description for this version. Can be formatted with [Markdown](https://daringfireball.net/projects/markdown/syntax). + +#### Example Request + + + + +```shell +curl \ + --request POST \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/versions \ + --data ' + { + "version": { + "version": "1.2.3", + "description": "A new version" + } + } + ' +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Content-Type" => "application/json", + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.post("/api/v2/box/myuser/test/versions", json: { + version: { + version: "1.2.3", + description: "A new version" + } +}) + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a version](#read-a-version). + +### Update a version + +`PUT /api/v2/box/:username/:name/version/1.2.3` + +#### Arguments + +- `version` + - `version` - The version number of this version. + - `description` - A description for this version. Can be formatted with [Markdown][markdown]. + +#### Example Request + + + + +```shell +curl \ + --request PUT \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3 \ + --data ' + { + "version": { + "version": "1.2.3", + "description": "A new version" + } + } + ' +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Content-Type" => "application/json", + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.put("/api/v2/box/myuser/test/version/1.2.3", json: { + version: { + name: "1.2.3", + description: "A new version" + } +}) + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a version](#read-a-version). + +### Delete a version + +`DELETE /api/v2/box/:username/:name/version/:version` + +#### Example Request + + + + +```shell +curl \ + --request DELETE \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3 +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.delete("/api/v2/box/myuser/test/version/1.2.3") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a version](#read-a-version). + +### Release a version + +`PUT /api/v2/box/:username/:name/version/1.2.3/release` + +#### Example Request + + + + +```shell +curl \ + --request PUT \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/release +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.put("/api/v2/box/myuser/test/version/1.2.3/release") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a version](#read-a-version). + +### Revoke a version + +`PUT /api/v2/box/:username/:name/version/1.2.3/revoke` + +#### Example Request + + + + +```shell +curl \ + --request PUT \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/revoke +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.put("/api/v2/box/myuser/test/version/1.2.3/revoke") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a version](#read-a-version). + +## Providers + +### Read a provider + +`GET /api/v2/box/:username/:name/version/:version/provider/:provider/:architecture` + +#### Example Request + + + + +```shell +curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64 +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +```json +{ + "name": "virtualbox", + "hosted": false, + "hosted_token": null, + "original_url": "https://example.com/virtualbox-1.2.3.box", + "created_at": "2017-10-20T15:23:35.718Z", + "updated_at": "2017-10-20T15:23:35.718Z", + "download_url": "https://vagrantcloud.com/myuser/boxes/test/versions/1.2.3/providers/virtualbox.box", + "checksum": "a59e7332e8bbe896f11f478fc61fa8a6", + "checksum_type": "md5", + "architecture": "amd64", + "default_architecture": true +} +``` + +### Create a provider + +`POST /api/v2/box/:username/:name/version/:version/providers` + +#### Arguments + +- `provider` + - `name` - The name of the provider. + - `url` - A valid URL to download this provider. If omitted, you must [upload](#upload-a-provider) the Vagrant box image for this provider to Vagrant Cloud before the provider can be used. + - `checksum` - Computed checksum of the box assets. When set, Vagrant will compute the checksum of the downloaded box asset and validate it matches this value. + - `checksum_type` - Type of checksum used. Currently supported values: md5, sha1, sha256, sha384, and sha512 + - `architecture` - Architecture of the Vagrant box image. Currently supported values: amd64, i386, arm, arm64, ppc64le, ppc64, mips64le, mips64, mipsle, mips, and s390x + - `default_architecture` - Set as the default architecture to be used when no architecture information is provided + +#### Example Request + + + + +```shell +curl \ + --request POST \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/providers \ + --data ' + { + "provider": { + "checksum": "a59e7332e8bbe896f11f478fc61fa8a6", + "checksum_type": "md5", + "name": "virtualbox", + "url": "https://example.com/virtualbox-1.2.3.box", + "architecture": "amd64", + "default_architecture": true + } + } + ' +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Content-Type" => "application/json", + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.post("/api/v2/box/myuser/test/version/1.2.3/providers", json: { + provider: { + name: "virtualbox", + url: "https://example.com/virtualbox-1.2.3.box", + architecture: "amd64", + default_architecture: true + } +}) + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a provider](#read-a-provider). + +### Update a provider + +`PUT /api/v2/box/:username/:name/version/:version/provider/:provider/:architecture` + +#### Arguments + +- `provider` + - `name` - The name of the provider. + - `url` - A valid URL to download this provider. If omitted, you must [upload](#upload-a-provider) the Vagrant box image for this provider to Vagrant Cloud before the provider can be used. + - `checksum` - Computed checksum of the box assets. When set, Vagrant will compute the checksum of the downloaded box asset and validate it matches this value. + - `checksum_type` - Type of checksum used. Currently supported values: md5, sha1, sha256, sha384, and sha512 + - `architecture` - Architecture of the Vagrant box image. Currently supported values: amd64, i386, arm, arm64, ppc64le, ppc64, mips64le, mips64, mipsle, mips, and s390x + - `default_architecture` - Set as the default architecture to be used when no architecture information is provided + +#### Example Request + + + + +```shell +curl \ + --request PUT \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64 \ + --data ' + { + "provider": { + "checksum": "a59e7332e8bbe896f11f478fc61fa8a6", + "checksum_type": "md5", + "name": "virtualbox", + "url": "https://example.com/virtualbox-1.2.3.box" + } + } + ' +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Content-Type" => "application/json", + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.put("/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64", json: { + provider: { + name: "virtualbox", + url: "https://example.com/virtualbox-1.2.3.box" + } +}) + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a provider](#read-a-provider). + +### Delete a provider + +`DELETE /api/v2/box/:username/:name/version/:version/provider/:provider/:architecture` + +#### Example Request + + + + +```shell +curl \ + --request DELETE \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64 +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.delete("/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64") + +if response.status.success? + # Success, the response attributes are available here. + p response.parse +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +Response body is identical to [Reading a provider](#read-a-provider). + +### Upload a provider + +`GET /api/v2/box/:username/:name/version/:version/provider/:provider/:architecture/upload` + +Prepares the provider for upload, and returns a JSON blob containing an `upload_path`. + +~> The upload must begin shortly after the response is returned, otherwise the URL will expire. If the URL expires, you can request this same API method again for a new upload URL. + +#### Example Request + + + + +```shell +response=$(curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64/upload) + +# Requires the jq command +upload_path=$(echo "$response" | jq .upload_path) + +curl \ + --request PUT \ + --upload-file virtualbox-1.2.3.box \ + "${upload_path}" +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64/upload") + +if response.status.success? + # Success, you can now upload the box image to the returned URL + upload_path = response.parse['upload_path'] + HTTP.post upload_path, body: File.open("virtualbox-1.2.3.box") +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +```json +{ + "upload_path": "https://archivist.hashicorp.com/v2/object/630e42d9-2364-2412-4121-18266770468e" +} +``` + +### Upload a provider directly to backend storage + +`GET /api/v2/box/:username/:name/version/:version/provider/:provider/:architecture/upload/direct` + +Prepares the provider for upload. This version of the upload API allows uploading the box asset directly to the backend storage. It requires +a two step process for uploading the box assets. First uploading the asset to storage and then finalizing the upload within Vagrant Cloud +via a provided callback. + +The request returns a JSON blob containing two fields: + +- `upload_path` - URL to `PUT` the box asset +- `callback` - Vagrant Cloud callback URL to finalize upload + +The box asset is uploaded directly to the URL provided by the `upload_path` via a `PUT` request. Once complete, a `PUT` request to the URL +provided in the `callback` field (complete with authentication header) finalizes the upload. + +~> The upload must begin shortly after the response is returned, otherwise the URL will expire. If the URL expires, you can request this same API method again for a new upload URL. + +#### Example Request + + + + +```shell +response=$(curl \ + --request GET \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64/upload/direct) + +# Requires the jq command +upload_path=$(echo "$response" | jq .upload_path) +callback=$(echo "$response" | jq .callback) + +curl \ + --request PUT \ + --upload-file virtualbox-1.2.3.box \ + "${upload_path}" + +curl + --request PUT \ + --header "Authorization: Bearer $VAGRANT_CLOUD_TOKEN" \ + "${callback}" +``` + + + + +```ruby +# gem install http, or add `gem "http"` to your Gemfile +require "http" +require "uri" + +api = HTTP.persistent("https://app.vagrantup.com").headers( + "Authorization" => "Bearer #{ENV['VAGRANT_CLOUD_TOKEN']}" +) + +response = api.get("/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64/upload") + +if response.status.success? + # Success, you can now upload the box image to the returned URL + upload_path = response.parse['upload_path'] + callback = response.parse['callback'] + # Upload the box asset + HTTP.post upload_path, body: File.open("virtualbox-1.2.3.box") + # Finalize the upload + api.put(URI.parse(callback).path) +else + # Error, inspect the `errors` key for more information. + p response.code, response.body +end +``` + + + + +#### Example Response + +```json +{ + "upload_path": "https://remote-storage.example.com/bucket/630e42d9-2364-2412-4121-18266770468e?auth=9023wqfda", + "callback": "https://app.vagrantup.com/api/v2/box/myuser/test/version/1.2.3/provider/virtualbox/amd64/upload/direct/630e42d9-2364-2412-4121-18266770468e" +} +``` + +[markdown]: https://daringfireball.net/projects/markdown/syntax diff --git a/website/content/vagrant-cloud/boxes/architecture.mdx b/website/content/vagrant-cloud/boxes/architecture.mdx new file mode 100644 index 000000000..ea6b8c309 --- /dev/null +++ b/website/content/vagrant-cloud/boxes/architecture.mdx @@ -0,0 +1,117 @@ +--- +layout: vagrant-cloud +page_title: Vagrant Box Architecture +description: "Vagrant box architecture and default architecture." +--- + +# Architecture for Vagrant boxes + +Providers for Vagrant boxes, in Vagrant version 2.4.0 and newer, can include +multiple architecture options. This allows you to have multiple instances +of one specific provider. The specific provider shares a common name for +artifacts of different architectures. + +For example, the `hashicorp/precise32` and `hashicorp/precise64` boxes each +include a provider for `virtualbox`. + +``` +hashicorp/precise32 + v1.0.0 + provider: virtualbox + +hashicorp/precise64 + v1.0.0 + provider: virtualbox +``` + +The addition of architecture now allows these to be combined into a single +box. Instead of having a `hashicorp/precise32` box for a 32-bit guest, and +a `hashicorp/precise64` box for a 64-bit guest, a single `hashicorp/precise` +box can provide both. + +``` +hashicorp/precise + v1.0.0 + provider: virtualbox, architecture: amd64 + provider: virtualbox, architecture: i386 +``` + +The Vagrant CLI will automatically match the provider architecture using the +detected local host architecture. If the Vagrant CLI cannot find a matching +architecture, it will attempt a +[special case match](/vagrant/vagrant-cloud/boxes/architecture#unknown-architecture). + +## Default architecture + +Vagrant Cloud allows you to optionally specify one architecture as the +"default architecture" for a provider. This enables the box owner to +control which architecture for the provider the Vagrant CLI uses +when architecture filtering is not available. By default, the first +provider in the configuration for a box version is the default architecture. + +Note, this functionality enables backwards compatiblity +with previous versions of the Vagrant CLI that do not support architecture +filtering when matching an appropriate provider. + +For example, the `2.0.0` version of the `hashicorp/precise` box is created and +a new `virtualbox` provider is created with `amd64` architecture. + +``` +hashicorp/precise + v2.0.0 + provider: virtualbox, architecture: amd64, default_architecture: true +``` + +Adding another `virtualbox` provider with `i386` architecture. + +``` +hashicorp/precise + v2.0.0 + provider: virtualbox, architecture: amd64, default_architecture: true + provider: virtualbox, architecture: i386, default_architecture: false +``` + +When the Vagrant CLI, prior to version 2.4.0, requests the `hashicorp/precise` +box with the `virtualbox` provider, it will receive the information from +the `virtualbox` provider with the `amd64` architecture because it is flagged +as being the default architecture. If, instead, the provider with `i386` +architecture should be returned, the `virtualbox` provider for the `i386` +architecture can be updated to be the default architecture. + +``` +hashicorp/precise + v2.0.0 + provider: virtualbox, architecture: amd64, default_architecture: false + provider: virtualbox, architecture: i386, default_architecture: true +``` + +Now the provider with the `i386` architecture will be returned. + +## Special cases + +There are two cases where Vagrant CLI versions with architecture support +will use the default architecture flag. + +### User requested + +If the user sets the [config.vm.box_architecture](/vagrant/docs/vagrantfile/machine_settings#config-vm-box_architecture) +option in their Vagrantfile to `nil`, the Vagrant CLI will use the +provider which has been flagged as the default architecture. + +### Unknown architecture + +The architecture value `unknown` combined with the default architecture +flag provides a special matching case for the Vagrant CLI. If the +[config.vm.box_architecture](/vagrant/docs/vagrantfile/machine_settings#config-vm-box_architecture) +option in the local Vagrantfile is configured with the default `:auto` +value, and no architecture matching the host platform can be found +for the desired provider, the Vagrant CLI will check for a matching +provider that is flagged as the default architecture and has an +architecture value of `unknown`. If that match is found, the Vagrant +CLI will use that provider. + +This special case matching was included so the Vagrant CLI would be +able to use boxes published to Vagrant Cloud prior to the introduction +of architecture metadata. All previously existing providers have a +default architecture value of `unknown` and are flagged as the default +architecture since they are the only provider to exist for a given name. diff --git a/website/content/vagrant-cloud/boxes/create.mdx b/website/content/vagrant-cloud/boxes/create.mdx index b58023dc9..05e67bab2 100644 --- a/website/content/vagrant-cloud/boxes/create.mdx +++ b/website/content/vagrant-cloud/boxes/create.mdx @@ -62,7 +62,7 @@ need to get an [access token](https://vagrantcloud.com/settings/security). Then, prepare the upload: ```shell-session -$ curl 'https://vagrantcloud.com/api/v1/box/USERNAME/BOX_NAME/version/VERSION/provider/PROVIDER_NAME/upload?access_token=ACCESS_TOKEN' +$ curl 'https://vagrantcloud.com/api/v2/box/USERNAME/BOX_NAME/version/VERSION/provider/PROVIDER_NAME/ARCHITECTURE_NAME/upload?access_token=ACCESS_TOKEN' ``` This should return something like this: @@ -82,7 +82,7 @@ $ curl -X PUT --upload-file foo.box https://archivist.hashicorp.com/v1/object/63 When the upload finishes, you can verify it worked by making this request and matching the `hosted_token` it returns to the previously retrieved upload token. ```shell-session -$ curl 'https://vagrantcloud.com/api/v1/box/USERNAME/BOX_NAME/version/VERSION_NUMBER/provider/PROVIDER_NAME?access_token=ACCESS_TOKEN' +$ curl 'https://vagrantcloud.com/api/v2/box/USERNAME/BOX_NAME/version/VERSION_NUMBER/provider/PROVIDER_NAME/ARCHITECTURE_NAME?access_token=ACCESS_TOKEN' ``` Your box should then be available for download. diff --git a/website/data/vagrant-cloud-nav-data.json b/website/data/vagrant-cloud-nav-data.json index b09aa1104..a9a991781 100644 --- a/website/data/vagrant-cloud-nav-data.json +++ b/website/data/vagrant-cloud-nav-data.json @@ -18,6 +18,10 @@ "title": "Creating a New Version", "path": "boxes/create-version" }, + { + "title": "Box Provider Architecture", + "path": "boxes/architecture" + }, { "title": "Distributing", "path": "boxes/distributing" @@ -88,6 +92,15 @@ }, { "title": "API", - "path": "api" + "routes": [ + { + "title": "v2", + "path": "api/v2" + }, + { + "title": "v1", + "path": "api/v1" + } + ] } ]