vagrant_cloud 2.0.1 → 3.0.2

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
- SHA1:
3
- metadata.gz: b3fe589f6de0c2adb068af34c80e7e78740fc3ab
4
- data.tar.gz: 6894acccfd45d46a3adcfbeb2ff38fca58e24d2b
2
+ SHA256:
3
+ metadata.gz: d18cd817a0a9b3c10c3e1b16a0e7738ed92ea93b8b94e660fa3bfc4a1d66d14f
4
+ data.tar.gz: ad5d13564800b261a3144ab156d54de6c051623b57980416fa22522fa0bc0dec
5
5
  SHA512:
6
- metadata.gz: 86f7284a726434fcdde1d7dc860912a0c8cfdb8d6fb73181672ce07ec98e2a40028547c36f59fbaa3945c79139c302e610bd27d0a2df68619c1652ca888a0206
7
- data.tar.gz: 1d6615c95f7b4c1864bb220e18c42c71d675468e635975765ec2038ace6abf136dc2983f5b02a4569b2a8d36c7fa2320458fc96df22c0c839e6d646b59f7e3f0
6
+ metadata.gz: 55b01997babffc39900b35462c455df7d9bae1a6e9c3cf192b15f5d6d8de2b394ab82fee02a3e16ebfc163dc45930b36d26b2ca2d45ecea6ca74af9026863481
7
+ data.tar.gz: 154a11bbd5d86adde19251aa8da1e3da4441803a4c1fd2a59f5a86193218f3cefb676c4d3d7320c8d01608260388874a321993a0eb34e38ca137682c1ab2c06e
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.select { |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.
@@ -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,190 +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)
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
- begin
108
- box = get_box(name)
109
- box.data
110
- rescue RestClient::ResourceNotFound
111
- box = create_box(name, params)
112
- # If we've just created the box, we're done.
113
- return box
114
- end
115
-
116
- # Select elements from params that don't match what we have in the box
117
- # data. These are changed parameters and should be updated.
118
- update_params = params.select do |k, v|
119
- box.data[box.param_name(k)] != v
120
- end
121
-
122
- # Update the box with any params that had changed.
123
- box.update(update_params) unless update_params.empty?
124
-
125
- box
74
+ # Validate the current token
75
+ #
76
+ # @return [self]
77
+ def validate_token
78
+ client.request(path: "authenticate")
79
+ self
126
80
  end
127
81
 
128
- #--------------------
129
- # Old Box API Helpers
130
- #--------------------
131
-
132
- # REMOVED IN FAVOR OF CLIENT CLASS, but still exists to support any old clients
82
+ # Request a 2FA code is sent
133
83
  #
134
- # @param [String] method
135
- # @param [String] path
136
- # @param [Hash] params
137
- # @return [Hash]
138
- def request(method, path, params = {})
139
- headers = {}
140
-
141
- headers['Authorization'] = "Bearer #{access_token}" if access_token
142
-
143
- result = RestClient::Request.execute(
144
- method: method,
145
- url: url_base + path,
146
- payload: params,
147
- headers: headers,
148
- ssl_version: 'TLSv1'
149
- )
150
- result = JSON.parse(result)
151
- errors = result['errors']
152
- raise "Vagrant Cloud returned error: #{errors}" if errors
153
-
154
- 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))
155
91
  end
156
92
 
157
- private
158
-
159
- # @return [String]
160
- def url_base
161
- '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)
162
101
  end
163
102
 
164
- # @param [Array] args
165
- # @return [Hash]
166
- def box_params(*args)
167
- # Prepares a hash based on the *args array passed in.
168
- # Acceptable parameters are those documented by Hashicorp for the v1 API
169
- # at https://vagrantcloud.com/docs
103
+ protected
170
104
 
171
- # This dance is to simulate what we could have accomplished with **args
172
- # in Ruby 2.0+
173
- # This will silently discard any options that are not passed in as a
174
- # hash.
175
- # Find and remove the first hash we find in *args. Set params to an
176
- # empty hash if we weren't passed one.
177
- params = args.select { |v| v.is_a?(Hash) }.first
178
- if params.nil?
179
- params = {}
180
- else
181
- 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)
182
109
  end
183
-
184
- # Default boxes to public can be overridden by providing :is_private
185
- params[:is_private] = false unless params.key?(:is_private)
186
-
187
- params
188
110
  end
189
111
  end
190
112
  end