vagrant_cloud 2.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb644aa4c9adb9ab23859aabb4cf0ab6644822aa22732c8be4f4dff4dfc03d9d
4
- data.tar.gz: c2b3875c5d8423fce062e0a5b1e1dbc58871aa07eedc5ab5cd88ae323f7bf007
3
+ metadata.gz: ae5244a607d8479ce4eaeb153ad92eccc4b9cbbe66f7fbfe0dc3398eb1a1e4cc
4
+ data.tar.gz: 490dce0ee8f6348212d130e0dfb052c46019a63c79e6a8d773bc69e413b8cfd4
5
5
  SHA512:
6
- metadata.gz: 2fe5bab079a06e2ac5df5a6c572f3015cd4e428622aae819826fd456be0d663cab8ba70574f11d4a6fcd0e33547dd60d54c667aa7c9460a335d6ecc790c535ca
7
- data.tar.gz: edfd6d3934542bdf22fdf228736ba069198097fae2ab91cec5724efdc5fb9bf5b5ca2a2b26dfe48285d5a2a824273fc5d95e935ed3806fd0a142a722d80daffd
6
+ metadata.gz: 9776f4314c684123546653b38612f6e52e5cbd364d191383ed6e56a03824b2321c55e85fba99b669621babf346602f0ff799772bbb2cd583d0a70cf5010428ec
7
+ data.tar.gz: 7445dee9132c3babb2425f0f4f7d418372a10f273f5ecd9e4d4706c9e0bd752147efca6c49fb7209625161df0cfa9646149504a29fc4a43484323c08fde60280
data/README.md CHANGED
@@ -1,43 +1,149 @@
1
- vagrant_cloud
2
- =============
1
+ # vagrant_cloud
2
+
3
3
  Ruby client for the [Vagrant Cloud API](https://www.vagrantup.com/docs/vagrant-cloud/api.html).
4
4
 
5
- [![Build Status](https://img.shields.io/travis/hashicorp/vagrant_cloud/master.svg)](https://travis-ci.org/hashicorp/vagrant_cloud)
6
5
  [![Gem Version](https://img.shields.io/gem/v/vagrant_cloud.svg)](https://rubygems.org/gems/vagrant_cloud)
7
6
 
7
+ This library provides the functionality to create, modify, and delete boxes, versions,
8
+ and providers on Vagrant Cloud.
9
+
10
+ ## Usage
11
+
12
+ The Vagrant Cloud library provides two methods for interacting with the Vagrant Cloud API. The
13
+ first is direct interaction using a `VagrantCloud::Client` instance. The second is a basic
14
+ model based approach using a `VagrantCloud::Account` instance.
8
15
 
9
- This client allows to create, modify and delete *boxes*, *versions* and *providers*.
10
- The main entry point is an object referencing your *account*.
16
+ ### Direct Client
17
+
18
+ The `VagrantCloud::Client` class contains all the underlying functionality which with
19
+ `vagrant_cloud` library uses for communicating with Vagrant Cloud. It can be used directly
20
+ for quickly and easily sending requests to Vagrant Cloud. The `VagrantCloud::Client`
21
+ class will automatically handle any configured authentication, request parameter
22
+ structuring, and response validation. All API related methods in the `VagrantCloud::Client`
23
+ class will return `Hash` results.
24
+
25
+ Example usage (display box details):
11
26
 
12
- Usage
13
- -----
14
- Example usage:
15
27
  ```ruby
16
- account = VagrantCloud::Account.new('<username>', '<access_token>')
17
- box = account.ensure_box('my_box')
18
- version = box.ensure_version('0.0.1')
19
- provider = version.ensure_provider('virtualbox', 'http://example.com/foo.box')
28
+ require "vagrant_cloud"
20
29
 
21
- version.release
22
- puts provider.download_url
30
+ client = VagrantCloud::Client.new(access_token: "MY_TOKEN")
31
+ box = client.box_get(username: "hashicorp", name: "bionic64")
32
+
33
+ puts "Box: #{box[:tag]} Description: #{box[:description]}"
34
+ ```
35
+
36
+ Example usage (creating box and releasing a new version):
37
+
38
+ ```ruby
39
+ require "vagrant_cloud"
40
+ require "net/http"
41
+
42
+ # Create a new client
43
+ client = VagrantCloud::Client.new(access_token: "MY_TOKEN")
44
+
45
+ # Create a new box
46
+ client.box_create(
47
+ username: "hashicorp",
48
+ name: "test-bionic64",
49
+ short_description: "Test Box",
50
+ long_description: "Testing box for an example",
51
+ is_private: false
52
+ )
53
+
54
+ # Create a new version
55
+ client.box_version_create(
56
+ username: "hashicorp",
57
+ name: "test-bionic64",
58
+ version: "1.0.0",
59
+ description: "Version 1.0.0 release"
60
+ )
61
+
62
+ # Create a new provider
63
+ client.box_version_provider_create(
64
+ username: "hashicorp",
65
+ name: "test-bionic64",
66
+ version: "1.0.0",
67
+ provider: "virtualbox"
68
+ )
69
+
70
+ # Request box upload URL
71
+ upload_url = client.box_version_provider_upload(
72
+ username: "hashicorp",
73
+ name: "test-bionic64",
74
+ version: "1.0.0",
75
+ provider: "virtualbox"
76
+ )
77
+
78
+ # Upload box asset
79
+ uri = URI.parse(upload_url[:upload_path])
80
+ request = Net::HTTP::Post.new(uri)
81
+ box = File.open(BOX_PATH, "rb")
82
+ request.set_form([["file", box]], "multipart/form-data")
83
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme.eql?("https")) do |http|
84
+ http.request(request)
85
+ end
86
+
87
+ # Release the version
88
+ client.box_version_release(
89
+ username: "hashicorp",
90
+ name: "test-bionic64",
91
+ version: "1.0.0"
92
+ )
93
+ ```
94
+
95
+ ### Simple Models
96
+
97
+ The `VagrantCloud::Account` class is the entry point for using simple models to
98
+ interact with Vagrant Cloud.
99
+
100
+ Example usage (display box details):
101
+
102
+ ```ruby
103
+ require "vagrant_cloud"
104
+
105
+ account = VagrantCloud::Account.new(access_token: "MY_TOKEN")
106
+ org = account.organization(name: "hashicorp")
107
+ box = org.boxes.detect { |b| b.name == "bionic64" }
108
+
109
+ puts "Box: #{box[:tag]} Description: #{box[:description]}"
23
110
  ```
24
111
 
25
- __NOTE:__ As of version 2.0.0, the CLI has been deprecated in favor of the `vagrant cloud`
26
- command. More information about how to use the `vagrant cloud` command can be found
27
- on the [Vagrant documentation](https://www.vagrantup.com/docs/cli/cloud.html).
28
-
29
- Example CLI usage:
30
- Create a version and provider within an existing Box, upload a file to be hosted by Vagrant Cloud, and release the version
31
- ```sh
32
- vagrant_cloud create_version --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION
33
- vagrant_cloud create_provider --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION
34
- vagrant_cloud upload_file --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION --provider_file_path $PACKAGE_PATH
35
- vagrant_cloud release_version --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION
112
+ Example usage (creating box and releasing a new version):
113
+
114
+ ```ruby
115
+ require "vagrant_cloud"
116
+
117
+ # Load our account
118
+ account = VagrantCloud::Account.new(access_token: "MY_TOKEN")
119
+
120
+ # Load organization
121
+ org = account.organization(name: "hashicorp")
122
+
123
+ # Create a new box
124
+ box = org.add_box("test-bionic64")
125
+ box.description = "Testing box for an example"
126
+ box.short_description = "Test Box"
127
+
128
+ # Create a new version
129
+ version = box.add_version("1.0.0")
130
+ version.description = "Version 1.0.0 release"
131
+
132
+ # Create a new provider
133
+ provider = version.add_provider("virtualbox")
134
+
135
+ # Save the box, version, and provider
136
+ box.save
137
+
138
+ # Upload box asset
139
+ provider.upload(path: BOX_PATH)
140
+
141
+ # Release the version
142
+ version.release
36
143
  ```
37
- If you installed vagrant_cloud with bundler, then you may have to invoke using `bundle exec vagrant_cloud`
38
144
 
39
- Development & Contributing
40
- --------------------------
145
+ ## Development & Contributing
146
+
41
147
  Pull requests are very welcome!
42
148
 
43
149
  Install dependencies:
@@ -50,18 +156,18 @@ Run the tests:
50
156
  bundle exec rspec
51
157
  ```
52
158
 
53
- Check the code syntax:
54
- ```
55
- bundle exec rubocop
56
- ```
159
+ ## Releasing
57
160
 
58
161
  Release a new version:
59
162
 
60
- 1. Bump the version in `vagrant_cloud.gemspec`, merge to master.
61
- 2. Push a new tag to master.
62
- 3. Release to RubyGems with `bundle exec rake release`.
163
+ 1. Update the version in the `version.txt` file
164
+ 1. Commit the change to master
165
+ 1. Create a new version tag in git: `git tag vX.X.X`
166
+ 1. Push the new tag and master to GitHub `git push origin main --tags`
167
+
168
+ The new release will be automatically built and published.
169
+
170
+ ## History
63
171
 
64
- History
65
- -------
66
- This gem has been developed and maintained by [Cargo Media](https://www.cargomedia.ch) since April 2014.
67
- HashiCorp became the official maintainer in October 2017.
172
+ - This gem was developed and maintained by [Cargo Media](https://www.cargomedia.ch) from April 2014 until October 2017.
173
+ - The `vagrant_cloud` CLI tool included in this RubyGem has been deprecated and removed. See `vagrant cloud` for a replacement.
data/lib/vagrant_cloud.rb CHANGED
@@ -1,11 +1,21 @@
1
- require 'json'
2
- require 'rest_client'
1
+ require "excon"
2
+ require "log4r"
3
+ require "json"
4
+ require "securerandom"
5
+ require "set"
6
+ require 'singleton'
7
+ require "thread"
3
8
 
4
- require 'vagrant_cloud/errors'
5
-
6
- require 'vagrant_cloud/account'
7
- require 'vagrant_cloud/box'
8
- require 'vagrant_cloud/version'
9
- require 'vagrant_cloud/provider'
10
- require 'vagrant_cloud/search'
11
- require 'vagrant_cloud/client'
9
+ module VagrantCloud
10
+ autoload :Account, "vagrant_cloud/account"
11
+ autoload :Box, "vagrant_cloud/box"
12
+ autoload :Client, "vagrant_cloud/client"
13
+ autoload :Data, "vagrant_cloud/data"
14
+ autoload :Error, "vagrant_cloud/error"
15
+ autoload :Instrumentor, "vagrant_cloud/instrumentor"
16
+ autoload :Logger, "vagrant_cloud/logger"
17
+ autoload :Organization, "vagrant_cloud/organization"
18
+ autoload :Response, "vagrant_cloud/response"
19
+ autoload :Search, "vagrant_cloud/search"
20
+ autoload :VERSION, "vagrant_cloud/version"
21
+ end
@@ -1,195 +1,112 @@
1
1
  module VagrantCloud
2
+ # VagrantCloud account
2
3
  class Account
3
- attr_accessor :username
4
- attr_accessor :access_token
5
-
6
- # @param [String] username
7
- # @param [String] access_token
8
- def initialize(username, access_token, custom_server = nil)
9
- @username = username
10
- @access_token = access_token
11
- @client = Client.new(access_token, custom_server)
12
- end
13
-
14
- #---------------------------
15
- # Authentication API Helpers
16
- #---------------------------
17
-
18
- # @param [String] password
19
- # @param [String] description
20
- # @param [String] 2FA code
21
- # @return [Hash] response body
22
- def create_token(password, description = nil, code = nil)
23
- token_data_params = {
24
- token: { description: description },
25
- user: { login: @username, password: password },
26
- two_factor: code
27
- }.delete_if { |_, v| v.nil? }
28
-
29
- token_response = @client.request('post', '/authenticate', token_data_params)
30
- token_response
31
- end
32
-
33
- # @param [String] token
34
- def delete_token(access_token = nil)
35
- token_response = @client.request('delete', '/authenticate', nil, access_token)
36
- token_response
37
- end
38
-
39
- # Validates a token on the account or a one-off validation token request.
40
- # Will return nil if token is valid, otherwise will return Hash of response
41
- # from Vagrant Cloud
4
+ # @return [Client]
5
+ attr_reader :client
6
+ # @return [String] username of this account
7
+ attr_reader :username
8
+ # @return [Instrumentor::Collection] Instrumentor in use
9
+ attr_reader :instrumentor
10
+
11
+ # Create a new Account instance
42
12
  #
43
- # @param [String] access_token
44
- # @return [Hash] response body
45
- def validate_token(access_token = nil)
46
- token_response = @client.request('get', '/authenticate', nil, access_token)
47
- token_response
13
+ # @param [String] access_token Authentication token
14
+ # @param [Client] client Client to use for account
15
+ # @param [String] custom_server Custom server URL for client
16
+ # @param [Integer] retry_count Number of retries on idempotent requests
17
+ # @param [Integer] retry_interval Number of seconds to wait between requests
18
+ # @param [Instrumentor::Core] instrumentor Instrumentor to use
19
+ # @return [Account]
20
+ def initialize(access_token: nil, client: nil, custom_server: nil, retry_count: nil, retry_interval: nil, instrumentor: nil)
21
+ raise ArgumentError, "Account accepts `access_token` or `client` but not both" if
22
+ client && access_token
23
+ raise TypeError, "Expected `#{Client.name}` but received `#{client.class.name}`" if
24
+ client && !client.is_a?(Client)
25
+
26
+ if client
27
+ @client = client
28
+ else
29
+ @client = Client.new(
30
+ access_token: access_token,
31
+ url_base: custom_server,
32
+ retry_count: retry_count,
33
+ retry_interval: retry_interval,
34
+ instrumentor: instrumentor
35
+ )
36
+ end
37
+ setup!
48
38
  end
49
39
 
50
- # @param [String] delivery_method
51
- # @param [String] password
52
- # @return [Hash] response body
53
- def request_2fa_code(delivery_method, password)
54
- twofa_code_params = {
55
- two_factor: { delivery_method: delivery_method },
56
- user: { login: @username, password: password }
57
- }
58
-
59
- code_response = @client.request('post', '/two-factor/request-code', twofa_code_params)
60
- code_response
40
+ # @return [Search]
41
+ def searcher
42
+ Search.new(account: self)
61
43
  end
62
44
 
63
45
  #---------------------------
64
- # Organization API Helpers
46
+ # Authentication API Helpers
65
47
  #---------------------------
66
48
 
67
- # @param [String] - organization
68
- # @return [Hash]
69
- def read_organization(org = nil)
70
- if org
71
- name = org
72
- else
73
- name = @username
74
- end
75
-
76
- @client.request('get', "/user/#{name}")
77
- end
78
-
79
- #--------------------
80
- # Old Box API Helpers
81
- #--------------------
82
-
83
- # @param [String] name
84
- # @param [Hash] data
85
- # @return [Box]
86
- def get_box(name, data = nil)
87
- Box.new(self, name, data, nil, nil, @client.access_token, @client.url_base)
49
+ # Create a new access token
50
+ # @param [String] password Remote password
51
+ # @param [String] description Description of token
52
+ # @param [String] code 2FA code
53
+ # @return [Response::CreateToken]
54
+ def create_token(password:, description: Data::Nil, code: Data::Nil)
55
+ r = client.authentication_token_create(username: username,
56
+ password: password, description: description, code: code)
57
+
58
+ Response::CreateToken.new(
59
+ token: r[:token],
60
+ token_hash: r[:token_hash],
61
+ created_at: r[:created_at],
62
+ description: r[:description]
63
+ )
88
64
  end
89
65
 
90
- # @param [String] name
91
- # @param [Hash] args
92
- # @return [Box]
93
- def create_box(name, *args)
94
- params = box_params(*args)
95
- params[:name] = name
96
-
97
- data = @client.request('post', '/boxes', box: params)
98
- get_box(name, data)
66
+ # Delete the current token
67
+ #
68
+ # @return [self]
69
+ def delete_token
70
+ client.authentication_token_delete
71
+ self
99
72
  end
100
73
 
101
- # @param [String] name
102
- # @param [Hash] args
103
- # @return [Box]
104
- def ensure_box(name, *args)
105
- params = box_params(*args)
106
-
107
- # try to read the box data
108
- begin
109
- box = get_box(name)
110
- box.data
111
- rescue VagrantCloud::ClientError => err
112
- # Check if it's a 404 error. If so, then create
113
- # the missing box
114
- raise if err.error_code != 404
115
-
116
- box = create_box(name, params)
117
- # If we've just created the box, we're done.
118
- return box
119
- end
120
-
121
- # Select elements from params that don't match what we have in the box
122
- # data. These are changed parameters and should be updated.
123
- update_params = params.select do |k, v|
124
- box.data[box.param_name(k)] != v
125
- end
126
-
127
- # Update the box with any params that had changed.
128
- box.update(update_params) unless update_params.empty?
129
-
130
- box
74
+ # Validate the current token
75
+ #
76
+ # @return [self]
77
+ def validate_token
78
+ client.request(path: "authenticate")
79
+ self
131
80
  end
132
81
 
133
- #--------------------
134
- # Old Box API Helpers
135
- #--------------------
136
-
137
- # REMOVED IN FAVOR OF CLIENT CLASS, but still exists to support any old clients
82
+ # Request a 2FA code is sent
138
83
  #
139
- # @param [String] method
140
- # @param [String] path
141
- # @param [Hash] params
142
- # @return [Hash]
143
- def request(method, path, params = {})
144
- headers = {}
145
-
146
- headers['Authorization'] = "Bearer #{access_token}" if access_token
147
-
148
- result = RestClient::Request.execute(
149
- method: method,
150
- url: url_base + path,
151
- payload: params,
152
- headers: headers,
153
- ssl_version: 'TLSv1'
154
- )
155
- result = JSON.parse(result)
156
- errors = result['errors']
157
- raise "Vagrant Cloud returned error: #{errors}" if errors
158
-
159
- result
84
+ # @param [String] delivery_method Delivery method of 2FA
85
+ # @param [String] password Account password
86
+ # @return [Response]
87
+ def request_2fa_code(delivery_method:, password:)
88
+ r = client.authentication_request_2fa_code(username: username,
89
+ password: password, delivery_method: delivery_method)
90
+ Response::Request2FA.new(destination: r.dig(:two_factor, :obfuscated_destination))
160
91
  end
161
92
 
162
- private
163
-
164
- # @return [String]
165
- def url_base
166
- 'https://vagrantcloud.com/api/v1'
93
+ # Fetch the requested organization
94
+ #
95
+ # @param [String] name Organization name
96
+ # @return [Organization]
97
+ def organization(name: nil)
98
+ org_name = name || username
99
+ r = client.organization_get(name: org_name)
100
+ Organization.load(account: self, **r)
167
101
  end
168
102
 
169
- # @param [Array] args
170
- # @return [Hash]
171
- def box_params(*args)
172
- # Prepares a hash based on the *args array passed in.
173
- # Acceptable parameters are those documented by Hashicorp for the v1 API
174
- # at https://vagrantcloud.com/docs
103
+ protected
175
104
 
176
- # This dance is to simulate what we could have accomplished with **args
177
- # in Ruby 2.0+
178
- # This will silently discard any options that are not passed in as a
179
- # hash.
180
- # Find and remove the first hash we find in *args. Set params to an
181
- # empty hash if we weren't passed one.
182
- params = args.select { |v| v.is_a?(Hash) }.first
183
- if params.nil?
184
- params = {}
185
- else
186
- args.delete_if { |v| v == params }
105
+ def setup!
106
+ if client.access_token
107
+ r = client.request(path: "authenticate")
108
+ @username = r.dig(:user, :username)
187
109
  end
188
-
189
- # Default boxes to public can be overridden by providing :is_private
190
- params[:is_private] = false unless params.key?(:is_private)
191
-
192
- params
193
110
  end
194
111
  end
195
112
  end