vagrant_cloud 1.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d6540c7adaf6171dba9ebfc84c6e7318668bf162
4
- data.tar.gz: 0d1670e8ab10effb005977fbad33a093098bf56d
2
+ SHA256:
3
+ metadata.gz: 360b98c309f3b2804dce161d08972266978ac3059dbc5516bd12b52e5c1fff98
4
+ data.tar.gz: d258cb4d89be2bc698e4f087e8a504e2ba9a4e085ff9ab5e48c24c262926784f
5
5
  SHA512:
6
- metadata.gz: fdac04b8abf7afda5bd6346aff9d1501adc381fb7e2b92b068e8c8c5fb5b2f4ca6bec3e601ace3f6fd1d7f44852d1f16e51866a0124881eebf40a4a48228d032
7
- data.tar.gz: 586674a4c7a71c102d2a71e9ea2b13f205e65bac47cc95096d0defc891ca18a43001eacd09ebfc168e5ab66894e5db76d14859b66024d533af394d7e692f47ea
6
+ metadata.gz: 4dadf15e12aa55529ff8023f73c19a59f4882496003246cca6ee5e2b798f86004beb343b68c97dcda465205a227312ba49023ba91b83429ac24da8cb919c8372
7
+ data.tar.gz: b46249ed808cf36ffe8e65f0e234ef7fb291e9648e8cc1d8e044c1fe0ac7b1da2814eda39a14b048728bd5376b7a14a24a31d2ab68ab56f832e4ea0c2ebafb4b
data/LICENSE CHANGED
@@ -1,6 +1,7 @@
1
1
  The MIT License (MIT)
2
2
 
3
3
  Copyright (c) 2014 Cargo Media
4
+ Copyright (c) 2017 HashiCorp
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
7
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,39 +1,149 @@
1
- vagrant_cloud
2
- =============
3
- Minimalistic ruby client for the [HashiCorp Atlas API](https://vagrantcloud.com/docs) (previously *Vagrant Cloud API*).
1
+ # vagrant_cloud
2
+
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/cargomedia/vagrant_cloud/master.svg)](https://travis-ci.org/cargomedia/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]}"
23
34
  ```
24
35
 
25
- Example CLI usage:
26
- Create a version and provider within an existing Box, upload a file to be hosted by Vagrant/Atlas, and release the version
27
- ```sh
28
- vagrant_cloud create_version --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION
29
- vagrant_cloud create_provider --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION
30
- vagrant_cloud upload_file --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION --provider_file_path $PACKAGE_PATH
31
- vagrant_cloud release_version --username $USERNAME --token $VAGRANT_CLOUD_TOKEN --box $BOX_NAME --version $BOX_VERSION
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
+ )
32
93
  ```
33
- If you installed vagrant_cloud with bundler, then you may have to invoke using `bundle exec vagrant_cloud`
34
94
 
35
- Development & Contributing
36
- --------------------------
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]}"
110
+ ```
111
+
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
143
+ ```
144
+
145
+ ## Development & Contributing
146
+
37
147
  Pull requests are very welcome!
38
148
 
39
149
  Install dependencies:
@@ -46,13 +156,18 @@ Run the tests:
46
156
  bundle exec rspec
47
157
  ```
48
158
 
49
- Check the code syntax:
50
- ```
51
- bundle exec rubocop
52
- ```
159
+ ## Releasing
53
160
 
54
161
  Release a new version:
55
162
 
56
- 1. Bump the version in `vagrant_cloud.gemspec`, merge to master.
57
- 2. Push a new tag to master.
58
- 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 master --tags`
167
+
168
+ The new release will be automatically built and published.
169
+
170
+ ## History
171
+
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,10 +1,21 @@
1
- module VagrantCloud
2
- require 'json'
3
- require 'rest_client'
1
+ require "excon"
2
+ require "log4r"
3
+ require "json"
4
+ require "securerandom"
5
+ require "set"
6
+ require 'singleton'
7
+ require "thread"
4
8
 
5
- require 'vagrant_cloud/account'
6
- require 'vagrant_cloud/box'
7
- require 'vagrant_cloud/version'
8
- require 'vagrant_cloud/provider'
9
- require 'vagrant_cloud/cli'
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"
10
21
  end
@@ -1,109 +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)
9
- @username = username
10
- @access_token = access_token
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
12
+ #
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!
11
38
  end
12
39
 
13
- # @param [String] name
14
- # @param [Hash]
15
- # @return [Box]
16
- def get_box(name, data = nil)
17
- Box.new(self, name, data)
40
+ # @return [Search]
41
+ def searcher
42
+ Search.new(account: self)
18
43
  end
19
44
 
20
- # @param [String] name
21
- # @param [Hash] args
22
- # @return [Box]
23
- def create_box(name, *args)
24
- params = box_params(*args)
25
- params[:name] = name
26
-
27
- data = request('post', '/boxes', box: params)
28
- get_box(name, data)
45
+ #---------------------------
46
+ # Authentication API Helpers
47
+ #---------------------------
48
+
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
+ )
29
64
  end
30
65
 
31
- # @param [String] name
32
- # @param [Hash] args
33
- # @return [Box]
34
- def ensure_box(name, *args)
35
- params = box_params(*args)
36
-
37
- begin
38
- box = get_box(name)
39
- box.data
40
- rescue RestClient::ResourceNotFound => e
41
- box = create_box(name, params)
42
- # If we've just created the box, we're done.
43
- return box
44
- end
45
-
46
- # Select elements from params that don't match what we have in the box
47
- # data. These are changed parameters and should be updated.
48
- update_params = params.select do |k, v|
49
- box.data[box.param_name(k)] != v
50
- end
51
-
52
- # Update the box with any params that had changed.
53
- box.update(update_params) unless update_params.empty?
54
-
55
- box
66
+ # Delete the current token
67
+ #
68
+ # @return [self]
69
+ def delete_token
70
+ client.authentication_token_delete
71
+ self
56
72
  end
57
73
 
58
- # @param [String] method
59
- # @param [String] path
60
- # @param [Hash] params
61
- # @return [Hash]
62
- def request(method, path, params = {})
63
- params[:access_token] = access_token
64
- result = RestClient::Request.execute(
65
- method: method,
66
- url: url_base + path,
67
- payload: params,
68
- ssl_version: 'TLSv1'
69
- )
70
- result = JSON.parse(result)
71
- errors = result['errors']
72
- raise "Vagrant Cloud returned error: #{errors}" if errors
73
- result
74
+ # Validate the current token
75
+ #
76
+ # @return [self]
77
+ def validate_token
78
+ client.request(path: "authenticate")
79
+ self
74
80
  end
75
81
 
76
- private
82
+ # Request a 2FA code is sent
83
+ #
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))
91
+ end
77
92
 
78
- # @return [String]
79
- def url_base
80
- '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)
81
101
  end
82
102
 
83
- # @param [Array] args
84
- # @return [Hash]
85
- def box_params(*args)
86
- # Prepares a hash based on the *args array passed in.
87
- # Acceptable parameters are those documented by Hashicorp for the v1 API
88
- # at https://vagrantcloud.com/docs
103
+ protected
89
104
 
90
- # This dance is to simulate what we could have accomplished with **args
91
- # in Ruby 2.0+
92
- # This will silently discard any options that are not passed in as a
93
- # hash.
94
- # Find and remove the first hash we find in *args. Set params to an
95
- # empty hash if we weren't passed one.
96
- params = args.select { |v| v.is_a?(Hash) }.first
97
- if params.nil?
98
- params = {}
99
- else
100
- 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)
101
109
  end
102
-
103
- # Default boxes to public can be overridden by providing :is_private
104
- params[:is_private] = false unless params.key?(:is_private)
105
-
106
- params
107
110
  end
108
111
  end
109
112
  end