hyperkit 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/hyperkit.svg)](https://badge.fury.io/rb/hyperkit) [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/jeffshantz/hyperkit/master) [![Build Status](https://travis-ci.org/jeffshantz/hyperkit.svg?branch=master)](https://travis-ci.org/jeffshantz/hyperkit) [![Coverage Status](https://coveralls.io/repos/github/jeffshantz/hyperkit/badge.svg?branch=master)](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: {}
|