hyperkit 1.0.0 → 1.0.2
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 +4 -4
- data/.travis.yml +19 -1
- data/Gemfile +3 -2
- data/README.md +14 -10
- data/hyperkit.gemspec +2 -2
- data/lib/hyperkit.rb +1 -1
- data/lib/hyperkit/client.rb +2 -0
- data/lib/hyperkit/client/certificates.rb +10 -14
- data/lib/hyperkit/client/containers.rb +40 -50
- data/lib/hyperkit/client/images.rb +37 -44
- data/lib/hyperkit/client/networks.rb +2 -2
- data/lib/hyperkit/client/operations.rb +15 -10
- data/lib/hyperkit/client/profiles.rb +84 -11
- data/lib/hyperkit/configurable.rb +45 -1
- data/lib/hyperkit/connection.rb +2 -2
- data/lib/hyperkit/default.rb +1 -1
- data/lib/hyperkit/error.rb +6 -6
- data/lib/hyperkit/middleware/follow_redirects.rb +2 -2
- data/lib/hyperkit/utility.rb +22 -0
- data/lib/hyperkit/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 31c1d9b05f7078a592ef2e0fcfaee2715cd16484
|
|
4
|
+
data.tar.gz: 12e2f1eabed87b1691627e1c1a884eaaaaedc94f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7608210cba76349bf7530ef5ea62e05be8b4e4e4f17654e0bbf772cc38554a0d7caf69297b483eccdba2bf0a61a8747996ca535b1d40584efa8456621e9edf25
|
|
7
|
+
data.tar.gz: a38a4bd0fb00a4368d8d2919472e3e3378123cc358fe9dd3f58ffe70f8b6b4a7bd95b06a543e574ebdf6baa5997abf20cbd617da4dc88b98ab4575662aa6a78f
|
data/.travis.yml
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
language: ruby
|
|
2
|
+
|
|
2
3
|
rvm:
|
|
4
|
+
- jruby
|
|
5
|
+
- rbx-2
|
|
3
6
|
- 1.9.3
|
|
4
|
-
|
|
7
|
+
- 2.0
|
|
8
|
+
- 2.1
|
|
9
|
+
- 2.2
|
|
10
|
+
|
|
11
|
+
bundler_args: --without development
|
|
12
|
+
|
|
13
|
+
sudo: false
|
|
14
|
+
|
|
15
|
+
matrix:
|
|
16
|
+
allow_failures:
|
|
17
|
+
- rvm: jruby
|
|
18
|
+
- rvm: rbx-2
|
|
19
|
+
- rvm: 1.9.3
|
|
20
|
+
|
|
21
|
+
notifications:
|
|
22
|
+
emails: true
|
data/Gemfile
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
|
+
gem 'rake'
|
|
4
|
+
|
|
3
5
|
group :development do
|
|
4
6
|
gem 'awesome_print', :require => 'ap'
|
|
5
7
|
gem 'guard-rspec', '~> 4.6'
|
|
6
8
|
gem 'hirb-unicode'
|
|
7
9
|
gem 'pry'
|
|
8
10
|
gem 'yard'
|
|
9
|
-
gem 'rake'
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
group :test do
|
|
13
14
|
gem 'coveralls', :require => false
|
|
14
15
|
gem 'multi_json', '~> 1.11.0'
|
|
15
16
|
gem 'rb-fsevent', '~> 0.9'
|
|
16
|
-
gem 'rspec', '~> 3.0
|
|
17
|
+
gem 'rspec', '~> 3.0'
|
|
17
18
|
gem 'simplecov', :require => false
|
|
18
19
|
gem 'vcr', '~> 3.0'
|
|
19
20
|
gem 'webmock', '~> 1.24.2'
|
data/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Hyperkit
|
|
2
2
|
|
|
3
|
+
[](https://badge.fury.io/rb/hyperkit) [](http://rubydoc.info/github/jeffshantz/hyperkit/master) [](https://travis-ci.org/jeffshantz/hyperkit) [](https://coveralls.io/github/jeffshantz/hyperkit?branch=master)
|
|
4
|
+
|
|
3
5
|
Hyperkit is a flat API wrapper for LXD, the next-generation hypervisor. It is
|
|
4
6
|
shamelessly based on the design of Octokit, the popular wrapper for the GitHub
|
|
5
7
|
API.
|
|
@@ -51,17 +53,17 @@ lxd.create_snapshot("test-container", "test-snapshot")
|
|
|
51
53
|
# container.
|
|
52
54
|
lxd2 = Hyperkit::Client.new(api_endpoint: "https://lxd2.example.com")
|
|
53
55
|
source = lxd2.init_migration("remote-container")
|
|
54
|
-
lxd.
|
|
56
|
+
lxd.migrate(source, "migrated-container")
|
|
55
57
|
```
|
|
56
58
|
|
|
57
59
|
Each method in the API documentation has at least one example of its usage. Please see the documentation for the following modules:
|
|
58
60
|
|
|
59
|
-
* [Certificates]()
|
|
60
|
-
* [Containers]()
|
|
61
|
-
* [Images]()
|
|
62
|
-
* [Networks]()
|
|
63
|
-
* [Operations]()
|
|
64
|
-
* [Profiles]()
|
|
61
|
+
* [Certificates](http://www.rubydoc.info/github/jeffshantz/hyperkit/master/Hyperkit/Client/Certificates)
|
|
62
|
+
* [Containers](http://www.rubydoc.info/github/jeffshantz/hyperkit/master/Hyperkit/Client/Containers)
|
|
63
|
+
* [Images](http://www.rubydoc.info/github/jeffshantz/hyperkit/master/Hyperkit/Client/Images)
|
|
64
|
+
* [Networks](http://www.rubydoc.info/github/jeffshantz/hyperkit/master/Hyperkit/Client/Networks)
|
|
65
|
+
* [Operations](http://www.rubydoc.info/github/jeffshantz/hyperkit/master/Hyperkit/Client/Operations)
|
|
66
|
+
* [Profiles](http://www.rubydoc.info/github/jeffshantz/hyperkit/master/Hyperkit/Client/Profiles)
|
|
65
67
|
|
|
66
68
|
## Requirements
|
|
67
69
|
|
|
@@ -98,7 +100,7 @@ client = Octokit::Client.new(api_endpoint: 'https://lxd.example.com:8443', verif
|
|
|
98
100
|
client.create_container("test-container", alias: "ubuntu/trusty/amd64")
|
|
99
101
|
```
|
|
100
102
|
|
|
101
|
-
[API methods]: http://
|
|
103
|
+
[API methods]: http://www.rubydoc.info/list/github/jeffshantz/hyperkit/master/method
|
|
102
104
|
|
|
103
105
|
## Authentication
|
|
104
106
|
|
|
@@ -160,13 +162,13 @@ Alternatively, you can simply copy your certificate file to the LXD server and
|
|
|
160
162
|
use the `lxc` tool to trust it:
|
|
161
163
|
|
|
162
164
|
```
|
|
163
|
-
|
|
165
|
+
$ lxc config trust add my-new-cert.crt
|
|
164
166
|
```
|
|
165
167
|
|
|
166
168
|
## API coverage
|
|
167
169
|
|
|
168
170
|
Hyperkit supports the entirety of [version 1.0 of the LXD
|
|
169
|
-
API](https://github.com/lxc/lxd/blob/master/
|
|
171
|
+
API](https://github.com/lxc/lxd/blob/master/doc/rest-api.md), but does not
|
|
170
172
|
support any of the Websocket API calls (e.g. `/1.0/events`).
|
|
171
173
|
|
|
172
174
|
## Asynchronous Operations
|
|
@@ -296,6 +298,8 @@ implementation, you will be responsible for providing patches in a timely
|
|
|
296
298
|
fashion. If critical issues for a particular implementation exist at the time
|
|
297
299
|
of a major release, support for that Ruby version may be dropped.
|
|
298
300
|
|
|
301
|
+
[travis]: https://travis-ci.org/jeffshantz/hyperkit
|
|
302
|
+
|
|
299
303
|
## Versioning
|
|
300
304
|
|
|
301
305
|
This library aims to adhere to [Semantic Versioning 2.0.0][semver]. Violations
|
data/hyperkit.gemspec
CHANGED
|
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
|
10
10
|
spec.email = ["hyperkit@jeffshantz.com"]
|
|
11
11
|
|
|
12
12
|
spec.summary = %q{Hyperkit is a flat API wrapper for LXD, the next-generation hypervisor}
|
|
13
|
-
spec.homepage = "
|
|
13
|
+
spec.homepage = "http://jeffshantz.github.io/hyperkit"
|
|
14
14
|
spec.license = "MIT"
|
|
15
15
|
|
|
16
16
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
|
@@ -28,6 +28,6 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
|
|
29
29
|
spec.add_dependency "activesupport", "~> 4.2.6"
|
|
30
30
|
spec.add_dependency "sawyer"
|
|
31
|
-
spec.add_development_dependency "bundler", "~> 1.
|
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.0"
|
|
32
32
|
|
|
33
33
|
end
|
data/lib/hyperkit.rb
CHANGED
data/lib/hyperkit/client.rb
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
require 'hyperkit/configurable'
|
|
24
24
|
require 'hyperkit/connection'
|
|
25
|
+
require 'hyperkit/utility'
|
|
25
26
|
require 'hyperkit/client/certificates'
|
|
26
27
|
require 'hyperkit/client/containers'
|
|
27
28
|
require 'hyperkit/client/images'
|
|
@@ -42,6 +43,7 @@ module Hyperkit
|
|
|
42
43
|
|
|
43
44
|
include Hyperkit::Configurable
|
|
44
45
|
include Hyperkit::Connection
|
|
46
|
+
include Hyperkit::Utility
|
|
45
47
|
include Hyperkit::Client::Certificates
|
|
46
48
|
include Hyperkit::Client::Containers
|
|
47
49
|
include Hyperkit::Client::Images
|
|
@@ -6,7 +6,7 @@ module Hyperkit
|
|
|
6
6
|
class Client
|
|
7
7
|
|
|
8
8
|
# Methods for the certificates API
|
|
9
|
-
#
|
|
9
|
+
#
|
|
10
10
|
# @see Hyperkit::Client
|
|
11
11
|
# @see https://github.com/lxc/lxd/blob/master/specs/rest-api.md
|
|
12
12
|
module Certificates
|
|
@@ -20,7 +20,7 @@ module Hyperkit
|
|
|
20
20
|
# "c782c0f3530a04a5b2b78fc5292b7500aef1299370288b5eeb0450a6613a2c82",
|
|
21
21
|
# "b7720e1eb839056158cf65d182865491a0403f766983b95f5098d05911bbff89"
|
|
22
22
|
# ]
|
|
23
|
-
def certificates
|
|
23
|
+
def certificates
|
|
24
24
|
response = get(certificates_path)
|
|
25
25
|
response.metadata.map { |path| path.split('/').last }
|
|
26
26
|
end
|
|
@@ -30,7 +30,7 @@ module Hyperkit
|
|
|
30
30
|
# @param cert [String] Certificate contents in PEM format
|
|
31
31
|
# @param options [Hash] Additional data to be passed
|
|
32
32
|
# @option options [String] :name Optional name for the certificate. If not specified, the host in the TLS header for the request is used.
|
|
33
|
-
# @option options [String] :password The trust password for that server. Only required if untrusted.
|
|
33
|
+
# @option options [String] :password The trust password for that server. Only required if untrusted.
|
|
34
34
|
# @return [Sawyer::Resource]
|
|
35
35
|
#
|
|
36
36
|
# @example Add trusted certificate
|
|
@@ -48,22 +48,20 @@ module Hyperkit
|
|
|
48
48
|
#
|
|
49
49
|
# @param fingerprint [String] Fingerprint of the certificate to retrieve. Can be a prefix, as long as it is unambigous
|
|
50
50
|
# @return [Sawyer::Resource] Certificate information
|
|
51
|
-
#
|
|
51
|
+
#
|
|
52
52
|
# @example Retrieve a certificate
|
|
53
53
|
# Hyperkit.certificate("c782c0f3530a04a5b2b78fc5292b7500aef1299370288b5eeb0450a6613a2c82") #=> {
|
|
54
|
-
# :certificate => "-----BEGIN CERTIFICATE-----\nMIIEW...ceyg04=\n-----END CERTIFICATE-----\n",
|
|
55
|
-
# :fingerprint => "c782c0f3530a04a5b2b78fc5292b7500aef1299370288b5eeb0450a6613a2c82",
|
|
56
|
-
# :type => "client"
|
|
54
|
+
# :certificate => "-----BEGIN CERTIFICATE-----\nMIIEW...ceyg04=\n-----END CERTIFICATE-----\n",
|
|
55
|
+
# :fingerprint => "c782c0f3530a04a5b2b78fc5292b7500aef1299370288b5eeb0450a6613a2c82",
|
|
56
|
+
# :type => "client"
|
|
57
57
|
# }
|
|
58
58
|
#
|
|
59
59
|
# @example Retrieve a certificate by specifying a prefix of its fingerprint
|
|
60
60
|
# Hyperkit.certificate("c7") #=> {
|
|
61
|
-
# :certificate => "-----BEGIN CERTIFICATE-----\nMIIEW...ceyg04=\n-----END CERTIFICATE-----\n",
|
|
62
|
-
# :fingerprint => "c782c0f3530a04a5b2b78fc5292b7500aef1299370288b5eeb0450a6613a2c82",
|
|
63
|
-
# :type => "client"
|
|
61
|
+
# :certificate => "-----BEGIN CERTIFICATE-----\nMIIEW...ceyg04=\n-----END CERTIFICATE-----\n",
|
|
62
|
+
# :fingerprint => "c782c0f3530a04a5b2b78fc5292b7500aef1299370288b5eeb0450a6613a2c82",
|
|
63
|
+
# :type => "client"
|
|
64
64
|
# }
|
|
65
|
-
#
|
|
66
|
-
# @todo Write tests for the prefix
|
|
67
65
|
def certificate(fingerprint)
|
|
68
66
|
get(certificate_path(fingerprint)).metadata
|
|
69
67
|
end
|
|
@@ -78,8 +76,6 @@ module Hyperkit
|
|
|
78
76
|
#
|
|
79
77
|
# @example Delete a certificate by specifying a prefix of its fingerprint
|
|
80
78
|
# Hyperkit.delete_certificate("c7")
|
|
81
|
-
#
|
|
82
|
-
# @todo Write tests for the prefix
|
|
83
79
|
def delete_certificate(fingerprint)
|
|
84
80
|
delete(certificate_path(fingerprint)).metadata
|
|
85
81
|
end
|
|
@@ -6,7 +6,7 @@ module Hyperkit
|
|
|
6
6
|
class Client
|
|
7
7
|
|
|
8
8
|
# Methods for the containers API
|
|
9
|
-
#
|
|
9
|
+
#
|
|
10
10
|
# @see Hyperkit::Client
|
|
11
11
|
# @see https://github.com/lxc/lxd/blob/master/specs/rest-api.md
|
|
12
12
|
module Containers
|
|
@@ -198,7 +198,7 @@ module Hyperkit
|
|
|
198
198
|
|
|
199
199
|
response = post(containers_path, opts).metadata
|
|
200
200
|
handle_async(response, options[:sync])
|
|
201
|
-
|
|
201
|
+
|
|
202
202
|
end
|
|
203
203
|
|
|
204
204
|
# @!endgroup
|
|
@@ -233,7 +233,7 @@ module Hyperkit
|
|
|
233
233
|
# container = Hyperkit.container("test-container")
|
|
234
234
|
# container.ephemeral = true
|
|
235
235
|
# Hyperkit.update_container("test-container", container)
|
|
236
|
-
#
|
|
236
|
+
#
|
|
237
237
|
# @example Change container's AppArmor profile to 'unconfined'.
|
|
238
238
|
# container = Hyperkit.container("test-container")
|
|
239
239
|
#
|
|
@@ -248,11 +248,7 @@ module Hyperkit
|
|
|
248
248
|
def update_container(name, config, options={})
|
|
249
249
|
|
|
250
250
|
config = config.to_hash
|
|
251
|
-
|
|
252
|
-
# Stringify values in the config hash, since LXD chokes on non-String values
|
|
253
|
-
if config[:config]
|
|
254
|
-
config[:config] = config[:config].inject({}){|h,(k,v)| h[k.to_s] = v.to_s; h}
|
|
255
|
-
end
|
|
251
|
+
config[:config] = stringify_hash(config[:config]) if config[:config]
|
|
256
252
|
|
|
257
253
|
response = put(container_path(name), config).metadata
|
|
258
254
|
handle_async(response, options[:sync])
|
|
@@ -271,7 +267,7 @@ module Hyperkit
|
|
|
271
267
|
# @example Rename container "test" to "test2"
|
|
272
268
|
# Hyperkit.rename_container("test", "test2")
|
|
273
269
|
def rename_container(old_name, new_name, options={})
|
|
274
|
-
response = post(container_path(old_name), {
|
|
270
|
+
response = post(container_path(old_name), { name: new_name }).metadata
|
|
275
271
|
handle_async(response, options[:sync])
|
|
276
272
|
end
|
|
277
273
|
|
|
@@ -294,7 +290,7 @@ module Hyperkit
|
|
|
294
290
|
# Hyperkit.execute_command("test-container", "echo 'hello world'")
|
|
295
291
|
#
|
|
296
292
|
# @example Run a command (passed as an array) in container "test-container"
|
|
297
|
-
# Hyperkit.execute_command("test-container",
|
|
293
|
+
# Hyperkit.execute_command("test-container",
|
|
298
294
|
# ["bash", "-c", "echo 'hello world' > /tmp/test.txt"]
|
|
299
295
|
# )
|
|
300
296
|
#
|
|
@@ -311,10 +307,7 @@ module Hyperkit
|
|
|
311
307
|
opts = options.slice(:environment)
|
|
312
308
|
command = Shellwords.shellsplit(command) if command.is_a?(String)
|
|
313
309
|
|
|
314
|
-
|
|
315
|
-
if opts[:environment]
|
|
316
|
-
opts[:environment] = opts[:environment].inject({}){|h,(k,v)| h[k.to_s] = v.to_s; h}
|
|
317
|
-
end
|
|
310
|
+
opts[:environment] = stringify_hash(opts[:environment]) if opts[:environment]
|
|
318
311
|
|
|
319
312
|
response = post(File.join(container_path(container), "exec"), {
|
|
320
313
|
command: command,
|
|
@@ -504,7 +497,7 @@ module Hyperkit
|
|
|
504
497
|
# Prepare to migrate a container or snapshot. Generates source data to be passed to {#migrate}.
|
|
505
498
|
#
|
|
506
499
|
# Note that CRIU must be installed on the server to migrate a running container, or LXD will
|
|
507
|
-
# return a 500 error. On Ubuntu, you can install it with
|
|
500
|
+
# return a 500 error. On Ubuntu, you can install it with
|
|
508
501
|
# <code>sudo apt-get install criu</code>.
|
|
509
502
|
#
|
|
510
503
|
# @param name [String] Container name
|
|
@@ -562,7 +555,7 @@ module Hyperkit
|
|
|
562
555
|
source = container(container)
|
|
563
556
|
end
|
|
564
557
|
|
|
565
|
-
response = post(url, {
|
|
558
|
+
response = post(url, { migration: true })
|
|
566
559
|
agent = response.agent
|
|
567
560
|
|
|
568
561
|
source_data = {
|
|
@@ -583,7 +576,7 @@ module Hyperkit
|
|
|
583
576
|
# Migrate a remote container or snapshot to the server
|
|
584
577
|
#
|
|
585
578
|
# Note that CRIU must be installed on the server to migrate a running container, or LXD will
|
|
586
|
-
# return a 500 error. On Ubuntu, you can install it with
|
|
579
|
+
# return a 500 error. On Ubuntu, you can install it with
|
|
587
580
|
# <code>sudo apt-get install criu</code>.
|
|
588
581
|
#
|
|
589
582
|
# Also note that, unless overridden with the <code>profiles</code> parameter, if the source
|
|
@@ -641,7 +634,7 @@ module Hyperkit
|
|
|
641
634
|
opts["base-image"] = source.config["volatile.base_image"]
|
|
642
635
|
opts[:config] = options[:config] || source.config.to_hash
|
|
643
636
|
|
|
644
|
-
# If we're only copying the container, and configuration was explicitly
|
|
637
|
+
# If we're only copying the container, and configuration was explicitly
|
|
645
638
|
# overridden, then remove the volatile entries
|
|
646
639
|
if ! options[:move] && ! options.has_key?(:config)
|
|
647
640
|
opts[:config].delete_if { |k,v| k.to_s.start_with?("volatile") }
|
|
@@ -662,7 +655,7 @@ module Hyperkit
|
|
|
662
655
|
else
|
|
663
656
|
raise Hyperkit::MissingProfiles.new("Not all profiles applied to source container exist on the target LXD instance")
|
|
664
657
|
end
|
|
665
|
-
|
|
658
|
+
|
|
666
659
|
end
|
|
667
660
|
|
|
668
661
|
if options.has_key?(:ephemeral)
|
|
@@ -735,11 +728,11 @@ module Hyperkit
|
|
|
735
728
|
|
|
736
729
|
# Create a snapshot of a container
|
|
737
730
|
#
|
|
738
|
-
# If <code>stateful: true</code> is passed when creating a snapshot of a
|
|
731
|
+
# If <code>stateful: true</code> is passed when creating a snapshot of a
|
|
739
732
|
# running container, the container's runtime state will be stored in the
|
|
740
|
-
# snapshot. Note that CRIU must be installed on the server to create a
|
|
733
|
+
# snapshot. Note that CRIU must be installed on the server to create a
|
|
741
734
|
# stateful snapshot, or LXD will return a 500 error. On Ubuntu, you can
|
|
742
|
-
# install it with
|
|
735
|
+
# install it with
|
|
743
736
|
# <code>sudo apt-get install criu</code>.
|
|
744
737
|
#
|
|
745
738
|
# @async This method is asynchronous. See {Hyperkit::Configurable#auto_sync} for more information.
|
|
@@ -795,7 +788,7 @@ module Hyperkit
|
|
|
795
788
|
# @example Rename snapshot "test/snap1" to "snap2"
|
|
796
789
|
# Hyperkit.rename_snapshot("test", "snap1", "snap2")
|
|
797
790
|
def rename_snapshot(container, old_name, new_name, options={})
|
|
798
|
-
response = post(snapshot_path(container, old_name), {
|
|
791
|
+
response = post(snapshot_path(container, old_name), { name: new_name }).metadata
|
|
799
792
|
handle_async(response, options[:sync])
|
|
800
793
|
end
|
|
801
794
|
|
|
@@ -812,7 +805,7 @@ module Hyperkit
|
|
|
812
805
|
# @example Restore container "test" back to snapshot "snap1"
|
|
813
806
|
# Hyperkit.restore_snapshot("test", "snap1")
|
|
814
807
|
def restore_snapshot(container, snapshot, options={})
|
|
815
|
-
response = put(container_path(container), {
|
|
808
|
+
response = put(container_path(container), { restore: snapshot }).metadata
|
|
816
809
|
handle_async(response, options[:sync])
|
|
817
810
|
end
|
|
818
811
|
|
|
@@ -844,21 +837,21 @@ module Hyperkit
|
|
|
844
837
|
#
|
|
845
838
|
# @example Copy /etc/passwd in container "test" to the local file /tmp/passwd
|
|
846
839
|
# Hyperkit.pull_file("test", "/etc/passwd", "/tmp/passwd") #=> "/tmp/passwd"
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
840
|
+
def pull_file(container, source_file, dest_file)
|
|
841
|
+
contents = get(file_path(container, source_file), url_encode: false)
|
|
842
|
+
headers = last_response.headers
|
|
850
843
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
844
|
+
File.open(dest_file, "wb") do |f|
|
|
845
|
+
f.write(contents)
|
|
846
|
+
end
|
|
854
847
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
848
|
+
if headers["x-lxd-mode"]
|
|
849
|
+
File.chmod(headers["x-lxd-mode"].to_i(8), dest_file)
|
|
850
|
+
end
|
|
858
851
|
|
|
859
|
-
|
|
852
|
+
dest_file
|
|
860
853
|
|
|
861
|
-
|
|
854
|
+
end
|
|
862
855
|
|
|
863
856
|
# Write to a file in a container
|
|
864
857
|
#
|
|
@@ -896,14 +889,14 @@ module Hyperkit
|
|
|
896
889
|
headers["X-LXD-gid"] = options[:gid].to_s if options[:gid]
|
|
897
890
|
headers["X-LXD-mode"] = options[:mode].to_s(8).rjust(4, "0") if options[:mode]
|
|
898
891
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
892
|
+
if ! block_given?
|
|
893
|
+
content = options[:content].to_s
|
|
894
|
+
else
|
|
895
|
+
io = StringIO.new
|
|
896
|
+
yield io
|
|
897
|
+
io.rewind
|
|
898
|
+
content = io.read
|
|
899
|
+
end
|
|
907
900
|
|
|
908
901
|
post(file_path(container, dest_file), {
|
|
909
902
|
raw_body: content,
|
|
@@ -949,7 +942,7 @@ module Hyperkit
|
|
|
949
942
|
# Retrieve a list of logs for a container
|
|
950
943
|
#
|
|
951
944
|
# @param container [String] Container name
|
|
952
|
-
# @return [Array<String>] An array of log filenames
|
|
945
|
+
# @return [Array<String>] An array of log filenames
|
|
953
946
|
#
|
|
954
947
|
# @example Get list of logs for container "test-container"
|
|
955
948
|
# Hyperkit.logs("test-container")
|
|
@@ -1022,11 +1015,8 @@ module Hyperkit
|
|
|
1022
1015
|
def extract_container_options(name, options)
|
|
1023
1016
|
opts = options.slice(:architecture, :profiles, :ephemeral, :config).
|
|
1024
1017
|
merge({ name: name })
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
if opts[:config]
|
|
1028
|
-
opts[:config] = opts[:config].inject({}){|h,(k,v)| h[k.to_s] = v.to_s; h}
|
|
1029
|
-
end
|
|
1018
|
+
|
|
1019
|
+
opts[:config] = stringify_hash(opts[:config]) if opts[:config]
|
|
1030
1020
|
|
|
1031
1021
|
opts
|
|
1032
1022
|
end
|
|
@@ -1092,7 +1082,7 @@ module Hyperkit
|
|
|
1092
1082
|
opts
|
|
1093
1083
|
|
|
1094
1084
|
end
|
|
1095
|
-
|
|
1085
|
+
|
|
1096
1086
|
end
|
|
1097
1087
|
|
|
1098
1088
|
end
|
|
@@ -3,7 +3,7 @@ module Hyperkit
|
|
|
3
3
|
class Client
|
|
4
4
|
|
|
5
5
|
# Methods for the images API
|
|
6
|
-
#
|
|
6
|
+
#
|
|
7
7
|
# @see Hyperkit::Client
|
|
8
8
|
# @see https://github.com/lxc/lxd/blob/master/specs/rest-api.md
|
|
9
9
|
module Images
|
|
@@ -14,10 +14,10 @@ module Hyperkit
|
|
|
14
14
|
#
|
|
15
15
|
# @return [Array<String>] An array of image fingerprints
|
|
16
16
|
#
|
|
17
|
-
# @example Get list of images
|
|
17
|
+
# @example Get list of images
|
|
18
18
|
# Hyperkit.images #=> ["54c8caac1f61901ed86c68f24af5f5d3672bdc62c71d04f06df3a59e95684473",
|
|
19
19
|
# "97d97a3d1d053840ca19c86cdd0596cf1be060c5157d31407f2a4f9f350c78cc"]
|
|
20
|
-
def images
|
|
20
|
+
def images
|
|
21
21
|
response = get(images_path)
|
|
22
22
|
response.metadata.map { |path| path.split('/').last }
|
|
23
23
|
end
|
|
@@ -171,15 +171,15 @@ module Hyperkit
|
|
|
171
171
|
# @return [Sawyer::Resource] Operation or result, depending value of <code>:sync</code> parameter and/or {Hyperkit::Client::auto_sync}
|
|
172
172
|
#
|
|
173
173
|
# @example Import image by alias
|
|
174
|
-
# Hyperkit.create_image_from_remote("https://images.linuxcontainers.org:8443",
|
|
174
|
+
# Hyperkit.create_image_from_remote("https://images.linuxcontainers.org:8443",
|
|
175
175
|
# alias: "ubuntu/xenial/amd64")
|
|
176
|
-
#
|
|
176
|
+
#
|
|
177
177
|
# @example Import image by fingerprint
|
|
178
|
-
# Hyperkit.create_image_from_remote("https://images.linuxcontainers.org:8443",
|
|
178
|
+
# Hyperkit.create_image_from_remote("https://images.linuxcontainers.org:8443",
|
|
179
179
|
# fingerprint: "b1cf3d836196c316897d39872ff25e2d912ea933207b0c591334a67b290a5f1b")
|
|
180
180
|
#
|
|
181
181
|
# @example Import image and automatically update it when it is updated on the remote server
|
|
182
|
-
# Hyperkit.create_image_from_remote("https://images.linuxcontainers.org:8443",
|
|
182
|
+
# Hyperkit.create_image_from_remote("https://images.linuxcontainers.org:8443",
|
|
183
183
|
# alias: "ubuntu/xenial/amd64",
|
|
184
184
|
# auto_update: true)
|
|
185
185
|
#
|
|
@@ -200,7 +200,7 @@ module Hyperkit
|
|
|
200
200
|
|
|
201
201
|
opts[:source] = options.slice(:secret, :protocol, :certificate)
|
|
202
202
|
opts[:source].merge!({
|
|
203
|
-
type: "image",
|
|
203
|
+
type: "image",
|
|
204
204
|
mode: "pull",
|
|
205
205
|
server: server
|
|
206
206
|
})
|
|
@@ -209,7 +209,7 @@ module Hyperkit
|
|
|
209
209
|
raise Hyperkit::ImageIdentifierRequired.new("Please specify either :alias or :fingerprint")
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
-
opts[:properties] =
|
|
212
|
+
opts[:properties] = stringify_hash(options[:properties]) if options[:properties]
|
|
213
213
|
|
|
214
214
|
if options[:alias]
|
|
215
215
|
opts[:source][:alias] = options[:alias]
|
|
@@ -218,12 +218,12 @@ module Hyperkit
|
|
|
218
218
|
end
|
|
219
219
|
|
|
220
220
|
response = post(images_path, opts).metadata
|
|
221
|
-
|
|
221
|
+
handle_async(response, options[:sync])
|
|
222
222
|
end
|
|
223
223
|
|
|
224
224
|
# Import an image from a remote URL.
|
|
225
225
|
#
|
|
226
|
-
# Note: the URL passed to this method is <b>not</b> the URL of a tarball.
|
|
226
|
+
# Note: the URL passed to this method is <b>not</b> the URL of a tarball.
|
|
227
227
|
# Instead, the URL must return the following headers:
|
|
228
228
|
#
|
|
229
229
|
# * <code>LXD-Image-URL</code> - URL of the image tarball
|
|
@@ -277,11 +277,11 @@ module Hyperkit
|
|
|
277
277
|
def create_image_from_url(url, options={})
|
|
278
278
|
|
|
279
279
|
opts = options.slice(:filename, :public)
|
|
280
|
-
opts[:properties] =
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
280
|
+
opts[:properties] = stringify_hash(options[:properties]) if options[:properties]
|
|
281
|
+
opts[:source] = {
|
|
282
|
+
type: "url",
|
|
283
|
+
url: url
|
|
284
|
+
}
|
|
285
285
|
|
|
286
286
|
response = post(images_path, opts).metadata
|
|
287
287
|
handle_async(response, options[:sync])
|
|
@@ -317,14 +317,14 @@ module Hyperkit
|
|
|
317
317
|
def create_image_from_container(name, options={})
|
|
318
318
|
|
|
319
319
|
opts = options.slice(:filename, :public, :description)
|
|
320
|
-
opts[:properties] =
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
320
|
+
opts[:properties] = stringify_hash(options[:properties]) if options[:properties]
|
|
321
|
+
opts[:source] = {
|
|
322
|
+
type: "container",
|
|
323
|
+
name: name
|
|
324
|
+
}
|
|
325
325
|
|
|
326
326
|
response = post(images_path, opts).metadata
|
|
327
|
-
|
|
327
|
+
handle_async(response, options[:sync])
|
|
328
328
|
end
|
|
329
329
|
|
|
330
330
|
# Create an image from an existing snapshot.
|
|
@@ -358,14 +358,14 @@ module Hyperkit
|
|
|
358
358
|
def create_image_from_snapshot(container, snapshot, options={})
|
|
359
359
|
|
|
360
360
|
opts = options.slice(:filename, :public, :description)
|
|
361
|
-
opts[:properties] =
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
361
|
+
opts[:properties] = stringify_hash(options[:properties]) if options[:properties]
|
|
362
|
+
opts[:source] = {
|
|
363
|
+
type: "snapshot",
|
|
364
|
+
name: "#{container}/#{snapshot}"
|
|
365
|
+
}
|
|
366
366
|
|
|
367
367
|
response = post(images_path, opts).metadata
|
|
368
|
-
|
|
368
|
+
handle_async(response, options[:sync])
|
|
369
369
|
end
|
|
370
370
|
|
|
371
371
|
# Delete an image
|
|
@@ -385,7 +385,7 @@ module Hyperkit
|
|
|
385
385
|
# Hyperkit.delete_image("b41")
|
|
386
386
|
def delete_image(fingerprint, options={})
|
|
387
387
|
response = delete(image_path(fingerprint)).metadata
|
|
388
|
-
|
|
388
|
+
handle_async(response, options[:sync])
|
|
389
389
|
end
|
|
390
390
|
|
|
391
391
|
# @!endgroup
|
|
@@ -404,7 +404,7 @@ module Hyperkit
|
|
|
404
404
|
# @example Set image to be publicly-accessible
|
|
405
405
|
# Hyperkit.update_image("b1cf3d836196c316897d39872ff25e2d912ea933207b0c591334a67b290a5f1b",
|
|
406
406
|
# public: true)
|
|
407
|
-
#
|
|
407
|
+
#
|
|
408
408
|
# @example Overwrite image properties (removes all existing properties, sets "hello" property to "world")
|
|
409
409
|
# Hyperkit.update_image("b1cf3d836196c316897d39872ff25e2d912ea933207b0c591334a67b290a5f1b",
|
|
410
410
|
# properties: {
|
|
@@ -424,15 +424,15 @@ module Hyperkit
|
|
|
424
424
|
# )
|
|
425
425
|
def update_image(fingerprint, options={})
|
|
426
426
|
opts = options.slice(:public, :auto_update)
|
|
427
|
-
opts[:properties] =
|
|
427
|
+
opts[:properties] = stringify_hash(options[:properties]) if options[:properties]
|
|
428
428
|
|
|
429
429
|
put(image_path(fingerprint), opts).metadata
|
|
430
430
|
end
|
|
431
|
-
|
|
432
|
-
# Generate a secret for an image that can be used by an untrusted client
|
|
431
|
+
|
|
432
|
+
# Generate a secret for an image that can be used by an untrusted client
|
|
433
433
|
# to retrieve information on and/or export a private image.
|
|
434
434
|
#
|
|
435
|
-
# The secret is automatically invalidated 5 seconds after first using it
|
|
435
|
+
# The secret is automatically invalidated 5 seconds after first using it
|
|
436
436
|
# (e.g. after calling Hyperkit.image(fingerprint, secret: "...").
|
|
437
437
|
# This allows one to both retrieve the image information and then export it
|
|
438
438
|
# with the same secret.
|
|
@@ -443,7 +443,6 @@ module Hyperkit
|
|
|
443
443
|
#
|
|
444
444
|
# @param fingerprint [String] Fingerprint of the image. This can be a prefix of an image's fingerprint, as long as it is unambiguous.
|
|
445
445
|
# @return [Sawyer::Response] An asynchronous response containing the generated secret
|
|
446
|
-
# @todo Add test for fingerprint prefix
|
|
447
446
|
#
|
|
448
447
|
# @example Generate a secret for an image
|
|
449
448
|
# response = Hyperkit.create_image_secret("878cf0c70e14fec80aaf4d5e923670e68c45aa89fb05a481019bf086aec42649") #=> {
|
|
@@ -498,7 +497,7 @@ module Hyperkit
|
|
|
498
497
|
#
|
|
499
498
|
# @example Export private image via secret (created by {#create_image_secret})
|
|
500
499
|
# image = Hyperkit.image_by_alias("busybox/default/amd64")
|
|
501
|
-
# Hyperkit.export_image(image.fingerprint,
|
|
500
|
+
# Hyperkit.export_image(image.fingerprint,
|
|
502
501
|
# "/tmp", secret: "secret-issued-by-create_image_secret") => "/tmp/busybox-v1.21.1-lxc.tar.xz"
|
|
503
502
|
def export_image(fingerprint, output_dir, options={})
|
|
504
503
|
|
|
@@ -541,7 +540,7 @@ module Hyperkit
|
|
|
541
540
|
# "ubuntu/xenial/ppc64el",
|
|
542
541
|
# "ubuntu/xenial/s390x/default",
|
|
543
542
|
# "ubuntu/xenial/s390x"
|
|
544
|
-
# ]
|
|
543
|
+
# ]
|
|
545
544
|
def image_aliases
|
|
546
545
|
response = get(image_aliases_path)
|
|
547
546
|
response.metadata.map { |path| path.sub("#{image_aliases_path}/","") }
|
|
@@ -561,7 +560,7 @@ module Hyperkit
|
|
|
561
560
|
def image_alias(alias_name)
|
|
562
561
|
get(image_alias_path(alias_name)).metadata
|
|
563
562
|
end
|
|
564
|
-
|
|
563
|
+
|
|
565
564
|
# Assign an alias for an image
|
|
566
565
|
#
|
|
567
566
|
# @param fingerprint [String] Fingerprint of the image
|
|
@@ -659,12 +658,6 @@ module Hyperkit
|
|
|
659
658
|
"/1.0/images"
|
|
660
659
|
end
|
|
661
660
|
|
|
662
|
-
# Stringify any property values. LXD returns an error if
|
|
663
|
-
# integers are passed, for example
|
|
664
|
-
def stringify_properties(properties)
|
|
665
|
-
properties.inject({}){|h,(k,v)| h[k.to_s] = v.to_s; h}
|
|
666
|
-
end
|
|
667
|
-
|
|
668
661
|
end
|
|
669
662
|
|
|
670
663
|
end
|
|
@@ -3,7 +3,7 @@ module Hyperkit
|
|
|
3
3
|
class Client
|
|
4
4
|
|
|
5
5
|
# Methods for the networks API
|
|
6
|
-
#
|
|
6
|
+
#
|
|
7
7
|
# @see Hyperkit::Client
|
|
8
8
|
# @see https://github.com/lxc/lxd/blob/master/specs/rest-api.md
|
|
9
9
|
module Networks
|
|
@@ -38,7 +38,7 @@ module Hyperkit
|
|
|
38
38
|
def networks_path
|
|
39
39
|
"/1.0/networks"
|
|
40
40
|
end
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
end
|
|
@@ -5,7 +5,7 @@ module Hyperkit
|
|
|
5
5
|
class Client
|
|
6
6
|
|
|
7
7
|
# Methods for the operations API
|
|
8
|
-
#
|
|
8
|
+
#
|
|
9
9
|
# @see Hyperkit::Client
|
|
10
10
|
# @see https://github.com/lxc/lxd/blob/master/specs/rest-api.md
|
|
11
11
|
module Operations
|
|
@@ -14,7 +14,7 @@ module Hyperkit
|
|
|
14
14
|
#
|
|
15
15
|
# This will include operations that are currently executing, as well as
|
|
16
16
|
# operations that are paused until {#wait_for_operation} is called, at
|
|
17
|
-
# which time they will begin executing.
|
|
17
|
+
# which time they will begin executing.
|
|
18
18
|
#
|
|
19
19
|
# Additionally, since LXD keeps completed operations around for 5 seconds,
|
|
20
20
|
# the list returned may include recently completed operations.
|
|
@@ -40,7 +40,7 @@ module Hyperkit
|
|
|
40
40
|
# :created_at => 2016-04-14 21:30:59 UTC,
|
|
41
41
|
# :updated_at => 2016-04-14 21:30:59 UTC,
|
|
42
42
|
# :status => "Running",
|
|
43
|
-
# :status_code => 103,
|
|
43
|
+
# :status_code => 103,
|
|
44
44
|
# :resources => {
|
|
45
45
|
# :containers => ["/1.0/containers/test-container"]
|
|
46
46
|
# },
|
|
@@ -54,13 +54,13 @@ module Hyperkit
|
|
|
54
54
|
|
|
55
55
|
# Cancel a running operation
|
|
56
56
|
#
|
|
57
|
-
# Calling this will change the state of the operation to
|
|
57
|
+
# Calling this will change the state of the operation to
|
|
58
58
|
# <code>cancelling</code>. Note that the operation must be cancelable,
|
|
59
|
-
# which can be ascertained by calling {#operation} and checking the
|
|
59
|
+
# which can be ascertained by calling {#operation} and checking the
|
|
60
60
|
# <code>may_cancel</code> property.
|
|
61
61
|
#
|
|
62
62
|
# @param [String] uuid UUID of the operation
|
|
63
|
-
# @return [Sawyer::Resource]
|
|
63
|
+
# @return [Sawyer::Resource]
|
|
64
64
|
#
|
|
65
65
|
# @example Cancel an operation
|
|
66
66
|
# Hyperkit.cancel_operation("8b3dd0c2-9dad-4964-b00d-e21481a47fb8") => {}
|
|
@@ -70,10 +70,15 @@ module Hyperkit
|
|
|
70
70
|
|
|
71
71
|
# Wait for an asynchronous operation to complete
|
|
72
72
|
#
|
|
73
|
-
# Note that this is only needed if {
|
|
73
|
+
# Note that this is only needed if {Hyperkit::Configurable#auto_sync} has been
|
|
74
74
|
# set to <code>false</code>, or if the option <code>sync: false</code>
|
|
75
75
|
# has been passed to an asynchronous method.
|
|
76
76
|
#
|
|
77
|
+
# Note that, after an operation completes, LXD keeps it around for only 5
|
|
78
|
+
# seconds, so if you wait too long to call
|
|
79
|
+
# <code>wait_for_operation</code>, you'll get an exception when you
|
|
80
|
+
# eventually do call it.
|
|
81
|
+
#
|
|
77
82
|
# @param [String] uuid UUID of the operation
|
|
78
83
|
# @param [Fixnum] timeout Maximum time to wait (default: indefinite)
|
|
79
84
|
# @return [Sawyer::Resource] Operation result
|
|
@@ -99,7 +104,7 @@ module Hyperkit
|
|
|
99
104
|
|
|
100
105
|
sync = sync.nil? ? auto_sync : sync
|
|
101
106
|
|
|
102
|
-
if sync
|
|
107
|
+
if sync
|
|
103
108
|
wait_for_operation(response.id)
|
|
104
109
|
else
|
|
105
110
|
response
|
|
@@ -111,10 +116,10 @@ module Hyperkit
|
|
|
111
116
|
File.join(operations_path, uuid)
|
|
112
117
|
end
|
|
113
118
|
|
|
114
|
-
def operations_path
|
|
119
|
+
def operations_path
|
|
115
120
|
"/1.0/operations"
|
|
116
121
|
end
|
|
117
|
-
|
|
122
|
+
|
|
118
123
|
end
|
|
119
124
|
|
|
120
125
|
end
|
|
@@ -5,39 +5,112 @@ module Hyperkit
|
|
|
5
5
|
class Client
|
|
6
6
|
|
|
7
7
|
# Methods for the profiles API
|
|
8
|
-
#
|
|
8
|
+
#
|
|
9
9
|
# @see Hyperkit::Client
|
|
10
10
|
# @see https://github.com/lxc/lxd/blob/master/specs/rest-api.md
|
|
11
11
|
module Profiles
|
|
12
12
|
|
|
13
|
-
#
|
|
13
|
+
# List of profiles on the server
|
|
14
|
+
#
|
|
15
|
+
# @return [Array<String>] An array of profile names
|
|
16
|
+
#
|
|
17
|
+
# @example Get list of profiles
|
|
18
|
+
# Hyperkit.profiles #=> ["default", "docker"]
|
|
14
19
|
def profiles
|
|
15
20
|
response = get(profiles_path)
|
|
16
21
|
response.metadata.map { |path| path.split('/').last }
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
#
|
|
24
|
+
# Create a profile
|
|
25
|
+
#
|
|
26
|
+
# @param name [String] Profile name
|
|
27
|
+
# @param options [Hash] Additional data to be passed
|
|
28
|
+
# @option options [Hash] :config Profile configuration
|
|
29
|
+
# @option options [String] :description Profile description
|
|
30
|
+
# @option options [Hash] :devices Profile devices
|
|
31
|
+
# @return [Sawyer::Resource]
|
|
32
|
+
#
|
|
33
|
+
# @example Create profile with config
|
|
34
|
+
# Hyperkit.create_profile("test-profile", config: {
|
|
35
|
+
# "limits.memory" => "2GB",
|
|
36
|
+
# "limits.cpu" => 2,
|
|
37
|
+
# "raw.lxc" => "lxc.aa_profile = unconfined"
|
|
38
|
+
# })
|
|
39
|
+
#
|
|
40
|
+
# @example Create profile with devices
|
|
41
|
+
# Hyperkit.create_profile("test-profile", devices: {
|
|
42
|
+
# eth0: {
|
|
43
|
+
# nictype: "bridged",
|
|
44
|
+
# parent: "br-ext",
|
|
45
|
+
# type: "nic"
|
|
46
|
+
# }
|
|
47
|
+
# })
|
|
20
48
|
def create_profile(name, options={})
|
|
21
|
-
|
|
22
|
-
|
|
49
|
+
opts = options.merge(name: name)
|
|
50
|
+
opts[:config] = stringify_hash(opts[:config]) if opts[:config]
|
|
51
|
+
post(profiles_path, opts).metadata
|
|
23
52
|
end
|
|
24
53
|
|
|
25
|
-
#
|
|
54
|
+
# Retrieve a profile
|
|
55
|
+
#
|
|
56
|
+
# @param name [String] Profile name
|
|
57
|
+
# @return [Sawyer::Resource] Profile
|
|
58
|
+
#
|
|
59
|
+
# @example Retrieve profile 'test-profile'
|
|
60
|
+
# Hyperkit.profile("test-profile")
|
|
26
61
|
def profile(name)
|
|
27
62
|
get(profile_path(name)).metadata
|
|
28
63
|
end
|
|
29
64
|
|
|
30
|
-
#
|
|
65
|
+
# Update an existing profile
|
|
66
|
+
#
|
|
67
|
+
# @param name [String] Profile name
|
|
68
|
+
# @param options [Hash] Additional data to be passed
|
|
69
|
+
# @option options [Hash] :config Profile configuration. Existing configuration will be overwritten.
|
|
70
|
+
# @option options [String] :description Profile description
|
|
71
|
+
# @option options [Hash] :devices Profile devices. Existing devices will be overwritten.
|
|
72
|
+
# @return [Sawyer::Resource]
|
|
73
|
+
#
|
|
74
|
+
# @example Update profile with config (config is overwritten -- not merged)
|
|
75
|
+
# Hyperkit.update_profile("test-profile", config: {
|
|
76
|
+
# "limits.memory" => "4GB",
|
|
77
|
+
# "limits.cpu" => 4,
|
|
78
|
+
# "raw.lxc" => "lxc.aa_profile = unconfined"
|
|
79
|
+
# })
|
|
80
|
+
#
|
|
81
|
+
# @example Create profile with devices (devices are overwritten -- not merged)
|
|
82
|
+
# Hyperkit.create_profile("test-profile", devices: {
|
|
83
|
+
# eth0: {
|
|
84
|
+
# nictype: "bridged",
|
|
85
|
+
# parent: "br-int",
|
|
86
|
+
# type: "nic"
|
|
87
|
+
# }
|
|
88
|
+
# })
|
|
31
89
|
def update_profile(name, options={})
|
|
32
|
-
|
|
90
|
+
opts = options.except(:name)
|
|
91
|
+
opts[:config] = stringify_hash(opts[:config]) if opts[:config]
|
|
92
|
+
put(profile_path(name), opts).metadata
|
|
33
93
|
end
|
|
34
94
|
|
|
35
|
-
#
|
|
95
|
+
# Rename a profile
|
|
96
|
+
#
|
|
97
|
+
# @param old_name [String] Existing profile name
|
|
98
|
+
# @param new_name [String] New profile name
|
|
99
|
+
# @return [Sawyer::Resource]
|
|
100
|
+
#
|
|
101
|
+
# @example Rename profile 'test' to 'test2'
|
|
102
|
+
# Hyperkit.rename_profile("test", "test2")
|
|
36
103
|
def rename_profile(old_name, new_name)
|
|
37
104
|
post(profile_path(old_name), { name: new_name }).metadata
|
|
38
105
|
end
|
|
39
106
|
|
|
40
|
-
#
|
|
107
|
+
# Delete a profile
|
|
108
|
+
#
|
|
109
|
+
# @param name [String] Profile name
|
|
110
|
+
# @return [Sawyer::Resource]
|
|
111
|
+
#
|
|
112
|
+
# @example Delete profile 'test-profile'
|
|
113
|
+
# Hyperkit.delete_profile("test-profile")
|
|
41
114
|
def delete_profile(name)
|
|
42
115
|
delete(profile_path(name)).metadata
|
|
43
116
|
end
|
|
@@ -47,7 +120,7 @@ module Hyperkit
|
|
|
47
120
|
def profiles_path
|
|
48
121
|
"/1.0/profiles"
|
|
49
122
|
end
|
|
50
|
-
|
|
123
|
+
|
|
51
124
|
def profile_path(name)
|
|
52
125
|
File.join(profiles_path, name)
|
|
53
126
|
end
|
|
@@ -29,10 +29,54 @@ module Hyperkit
|
|
|
29
29
|
# @!attribute api_endpoint
|
|
30
30
|
# @return [String] the base URL for API requests (default: <code>https://localhost:8443/</code>)
|
|
31
31
|
# @!attribute auto_sync
|
|
32
|
+
# Whether to automatically wait for asynchronous operations to complete
|
|
33
|
+
#
|
|
34
|
+
# A good deal of the LXD API calls are asynchronous: you issue the call,
|
|
35
|
+
# and you receive an operation ID. You must then wait on the operation
|
|
36
|
+
# to complete. Each asynchronous method is marked as such in the Hyperkit
|
|
37
|
+
# documentation.
|
|
38
|
+
#
|
|
39
|
+
# <b>By default, Hyperkit provides auto-synchronization</b>. When you
|
|
40
|
+
# initiate an asynchronous operation, Hyperkit will automatically wait for
|
|
41
|
+
# the operation to complete before returning. If you wish to override
|
|
42
|
+
# this functionality, there are two ways to do this:
|
|
43
|
+
#
|
|
44
|
+
# * Pass <code>sync: false</code> to any of the asynchronous methods
|
|
45
|
+
# * Set <code>auto_sync</code> to <code>false</code> at the module or
|
|
46
|
+
# class level (see examples)
|
|
47
|
+
#
|
|
48
|
+
# Any asynchronous calls you issue after setting <code>auto_sync</code>
|
|
49
|
+
# to <code>false</code> will immediately return an operation ID instead of
|
|
50
|
+
# blocking. To ensure that an operation is complete, you will need to
|
|
51
|
+
# call {Hyperkit::Client::Operations#wait_for_operation}.
|
|
52
|
+
#
|
|
53
|
+
# Most users will likely want to keep <code>auto_sync</code> enabled for
|
|
54
|
+
# convenience.
|
|
55
|
+
#
|
|
56
|
+
# @example Create a container and automatically wait for it to complete (auto_sync is <code>true</code> by default)
|
|
57
|
+
# Hyperkit.create_container("test-container", alias: "ubuntu/trusty/amd64")
|
|
58
|
+
#
|
|
59
|
+
# @example Disable auto-synchronization at the module level
|
|
60
|
+
# Hyperkit.auto_sync = false
|
|
61
|
+
# op = Hyperkit.create_container("test-container", alias: "ubuntu/trusty/amd64")
|
|
62
|
+
# Hyperkit.wait_for_operation(op.id)
|
|
63
|
+
#
|
|
64
|
+
# @example Disable auto-synchronization at the class level
|
|
65
|
+
# client = Hyperkit::Client.new(auto_sync: false)
|
|
66
|
+
# op = client.create_container("test-container", alias: "ubuntu/trusty/amd64")
|
|
67
|
+
# client.wait_for_operation(op.id)
|
|
68
|
+
#
|
|
69
|
+
# @example Disable auto-synchronization, but enable it for one call by passing <code>sync: true</code>
|
|
70
|
+
# Hyperkit.auto_sync = false
|
|
71
|
+
# Hyperkit.create_container("test-container", alias: "ubuntu/trusty/amd64", sync: true)
|
|
72
|
+
# @example Enable auto-synchronization, but disable it for one call by passing <code>sync: false</code>
|
|
73
|
+
# Hyperkit.auto_sync = true
|
|
74
|
+
# op = Hyperkit.create_container("test-container", alias: "ubuntu/trusty/amd64", sync: false)
|
|
75
|
+
# Hyperkit.wait_for_operation(op.id)
|
|
32
76
|
# @return [String] whether to automatically wait on asynchronous events (default: <code>true</code>)
|
|
33
77
|
# @!attribute client_cert
|
|
34
78
|
# @return [String] the client certificate used to authenticate to the LXD server
|
|
35
|
-
# @!attribute client_key
|
|
79
|
+
# @!attribute client_key
|
|
36
80
|
# @return [String] the client key used to authenticate to the LXD server
|
|
37
81
|
# @!attribute default_media_type
|
|
38
82
|
# @return [String] the preferred media type (for API versioning, for example)
|
data/lib/hyperkit/connection.rb
CHANGED
|
@@ -166,9 +166,9 @@ module Hyperkit
|
|
|
166
166
|
if client_cert && File.exist?(client_cert)
|
|
167
167
|
conn_opts[:ssl][:client_cert] = OpenSSL::X509::Certificate.new(File.read(client_cert))
|
|
168
168
|
end
|
|
169
|
-
|
|
169
|
+
|
|
170
170
|
if client_key && File.exist?(client_key)
|
|
171
|
-
conn_opts[:ssl][:client_key] = OpenSSL::PKey::RSA.new(File.read(client_key))
|
|
171
|
+
conn_opts[:ssl][:client_key] = OpenSSL::PKey::RSA.new(File.read(client_key))
|
|
172
172
|
end
|
|
173
173
|
|
|
174
174
|
opts[:faraday] = Faraday.new(conn_opts)
|
data/lib/hyperkit/default.rb
CHANGED
|
@@ -46,7 +46,7 @@ module Hyperkit
|
|
|
46
46
|
# In Faraday 0.9, Faraday::Builder was renamed to Faraday::RackBuilder
|
|
47
47
|
RACK_BUILDER_CLASS = defined?(Faraday::RackBuilder) ? Faraday::RackBuilder : Faraday::Builder
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
# Default Faraday middleware stack
|
|
50
50
|
MIDDLEWARE = RACK_BUILDER_CLASS.new do |builder|
|
|
51
51
|
builder.use Hyperkit::Middleware::FollowRedirects
|
|
52
52
|
builder.use Hyperkit::Response::RaiseError
|
data/lib/hyperkit/error.rb
CHANGED
|
@@ -43,7 +43,7 @@ module Hyperkit
|
|
|
43
43
|
err
|
|
44
44
|
|
|
45
45
|
end
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
def self.from_async_operation(response)
|
|
48
48
|
|
|
49
49
|
return nil if response.nil? || response[:body].empty?
|
|
@@ -106,15 +106,15 @@ module Hyperkit
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
def self.error_for_500(response)
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
if response.body =~ /open: no such file or directory/i
|
|
111
111
|
Hyperkit::NotFound
|
|
112
112
|
elsif response.body =~ /open: is a directory/i
|
|
113
113
|
Hyperkit::BadRequest
|
|
114
|
-
|
|
114
|
+
else
|
|
115
115
|
Hyperkit::InternalServerError
|
|
116
116
|
end
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
private
|
|
@@ -146,7 +146,7 @@ module Hyperkit
|
|
|
146
146
|
|
|
147
147
|
def response_error
|
|
148
148
|
err = nil
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
if data.is_a?(Hash) && data[:error]
|
|
151
151
|
err = data[:error]
|
|
152
152
|
elsif data.is_a?(Hash) && data[:metadata]
|
|
@@ -247,7 +247,7 @@ module Hyperkit
|
|
|
247
247
|
# none is provided
|
|
248
248
|
class ImageIdentifierRequired < StandardError; end
|
|
249
249
|
|
|
250
|
-
# Raised when a method requires attributes of an alias to be
|
|
250
|
+
# Raised when a method requires attributes of an alias to be
|
|
251
251
|
# passed (e.g. description, traget), but none is provided
|
|
252
252
|
class AliasAttributesRequired < StandardError; end
|
|
253
253
|
|
|
@@ -2,14 +2,14 @@ require 'faraday'
|
|
|
2
2
|
require 'set'
|
|
3
3
|
|
|
4
4
|
module Hyperkit
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
module Middleware
|
|
7
7
|
|
|
8
8
|
# Public: Exception thrown when the maximum amount of requests is exceeded.
|
|
9
9
|
#
|
|
10
10
|
# Taken from Octokit, which was originally adapted from
|
|
11
11
|
# https://github.com/lostisland/faraday_middleware/blob/138766e/lib/faraday_middleware/response/follow_redirects.rb
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
class RedirectLimitReached < Faraday::Error::ClientError
|
|
14
14
|
attr_reader :response
|
|
15
15
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Hyperkit
|
|
2
|
+
|
|
3
|
+
# Utility methods for Hyperkit
|
|
4
|
+
module Utility
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# Stringify the keys and values of a hash
|
|
9
|
+
#
|
|
10
|
+
# LXD often chokes on non-String JSON values. This method simply
|
|
11
|
+
# takes a Hash and stringifies its keys and values. The result
|
|
12
|
+
# can then be converted to JSON and passed to LXD.
|
|
13
|
+
#
|
|
14
|
+
# @param input [Hash] Original Hash
|
|
15
|
+
# @return A copy of the Hash, with its keys and values stringified
|
|
16
|
+
def stringify_hash(input)
|
|
17
|
+
input.inject({}){|h,(k,v)| h[k.to_s] = v.to_s; h}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
data/lib/hyperkit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hyperkit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeff Shantz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-04-
|
|
11
|
+
date: 2016-04-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '1.
|
|
47
|
+
version: '1.0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '1.
|
|
54
|
+
version: '1.0'
|
|
55
55
|
description:
|
|
56
56
|
email:
|
|
57
57
|
- hyperkit@jeffshantz.com
|
|
@@ -87,8 +87,9 @@ files:
|
|
|
87
87
|
- lib/hyperkit/error.rb
|
|
88
88
|
- lib/hyperkit/middleware/follow_redirects.rb
|
|
89
89
|
- lib/hyperkit/response/raise_error.rb
|
|
90
|
+
- lib/hyperkit/utility.rb
|
|
90
91
|
- lib/hyperkit/version.rb
|
|
91
|
-
homepage:
|
|
92
|
+
homepage: http://jeffshantz.github.io/hyperkit
|
|
92
93
|
licenses:
|
|
93
94
|
- MIT
|
|
94
95
|
metadata: {}
|