oreno_lxdapi 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5b4a5211c7f6785c3c5dbb8ceaacf325fd5d8e7a
4
+ data.tar.gz: 05b9288e9946d99d70ec98f1dd250357bf2f72da
5
+ SHA512:
6
+ metadata.gz: 26fc8f5e94be979e32f7b295902ed2ed2b942eaeca80673983bfdff2836292eb45eeeb561a758ecb98800adbd6609354edda4a954230f0cde64927e6d49f8916
7
+ data.tar.gz: c20cc18f7b1b5ebfd8842dfa300a3c8673765280e1f4a351f6a980b146f3de1f4f2adf564910ed62f138adfa1c4ad9f8d0c063c7cf23e17bdac9665570354cf8
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oreno_lxdapi.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # Oreno LXD API Client for Ruby
2
+ [![Build Status](https://travis-ci.org/inokappa/oreno_lxdapi.svg)](https://travis-ci.org/inokappa/oreno_lxdapi)
3
+
4
+ ## Reference
5
+
6
+ - [LXD REST API](https://github.com/lxc/lxd/blob/master/specs/rest-api.md)
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'oreno_lxdapi'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install oreno_lxdapi
23
+
24
+ ## Usage
25
+
26
+ ### sample script and output
27
+
28
+ - sample
29
+
30
+ ```ruby
31
+ #!/usr/bin/env ruby
32
+
33
+ require 'oreno_lxdapi'
34
+
35
+ c = OrenoLxdapi::Client.new(
36
+ "unix:///var/lib/lxd/unix.socket",
37
+ "oreno-ubuntu-image",
38
+ "test01"
39
+ )
40
+ p c.class
41
+
42
+ puts "=== create_container"
43
+ p c.create_container(
44
+ {
45
+ :architecture => "2",
46
+ :limits_cpu => "1",
47
+ :ephemeral => false
48
+ }
49
+ )
50
+ sleep 5
51
+
52
+ puts "=== run_container"
53
+ p c.state_container("start", :timeout => 50)
54
+
55
+ puts "=== file_upload"
56
+ p c.file_upload("sample.txt", "/tmp/sample.txt")
57
+
58
+ puts "=== run_lxc_exec"
59
+ c.run_lxc_exec("pwd")
60
+ c.run_lxc_exec("ls -l /tmp/sample.txt")
61
+
62
+ puts "== describe_container"
63
+ metadata = c.describe_container
64
+ data = []
65
+ data << metadata['status']['status']
66
+ data << metadata['ephemeral']
67
+ data << metadata['status']['ips'].each { |ip| p ip['address'] if ip['interface'] == "eth0"}
68
+ p data
69
+
70
+ puts "=== stop_container"
71
+ p c.state_container("stop", :timeout => 50)
72
+ sleep 5
73
+ p c.delete_container
74
+ ```
75
+
76
+ - output
77
+
78
+ ```sh
79
+ OrenoLxdapi::Client
80
+
81
+ === create_container
82
+ "{\"type\":\"async\",\"status\":\"OK\",\"status_code\":100,\"metadata\":{\"id\":\"e01bac0f-30f4-4dae-91b5-f7fd7e7ea926\",\"class\":\"task\",\"created_at\":\"2016-01-02T19:51:40.161118734+09:00\",\"updated_at\":\"2016-01-02T19:51:40.161118734+09:00\",\"status\":\"Running\",\"status_code\":103,\"resources\":{\"containers\":[\"/1.0/containers/test01\"]},\"metadata\":null,\"may_cancel\":false,\"err\":\"\"},\"operation\":\"/1.0/operations/e01bac0f-30f4-4dae-91b5-f7fd7e7ea926\"}\n"
83
+
84
+ === run_container
85
+ I, [2016-01-02T19:51:45.177958 #22904] INFO -- : Starting Container...
86
+ I, [2016-01-02T19:51:48.242125 #22904] INFO -- : Starting Container...
87
+ "{\"type\":\"async\",\"status\":\"OK\",\"status_code\":100,\"metadata\":{\"id\":\"03e75986-9732-41c1-8ef3-71ad2dcc1112\",\"class\":\"task\",\"created_at\":\"2016-01-02T19:51:45.172238776+09:00\",\"updated_at\":\"2016-01-02T19:51:45.172238776+09:00\",\"status\":\"Running\",\"status_code\":103,\"resources\":{\"containers\":[\"/1.0/containers/test01\"]},\"metadata\":null,\"may_cancel\":false,\"err\":\"\"},\"operation\":\"/1.0/operations/03e75986-9732-41c1-8ef3-71ad2dcc1112\"}\n"
88
+
89
+ === file_upload
90
+ "{\"type\":\"sync\",\"status\":\"Success\",\"status_code\":200,\"metadata\":{},\"operation\":\"\"}\n"
91
+
92
+ === run_lxc_exec
93
+ /root
94
+ --w-r-xr-- 1 root root 0 Jan 2 10:51 /tmp/sample.txt
95
+
96
+ == describe_container
97
+ "xx.x.x.205"
98
+ ["Running", false, [{"interface"=>"eth0", "protocol"=>"IPV4", "address"=>"xx.x.x.205", "host_veth"=>"vethVIDOBX"}, {"interface"=>"lo", "protocol"=>"IPV4", "address"=>"127.0.0.1", "host_veth"=>""}, {"interface"=>"lo", "protocol"=>"IPV6", "address"=>"::1", "host_veth"=>""}]]
99
+
100
+ === stop_container
101
+ I, [2016-01-02T19:51:48.563168 #22904] INFO -- : Stopping Container...
102
+ "{\"type\":\"async\",\"status\":\"OK\",\"status_code\":100,\"metadata\":{\"id\":\"b244aead-bf3f-4e2a-9ad4-0168fa64d45b\",\"class\":\"task\",\"created_at\":\"2016-01-02T19:51:48.559000682+09:00\",\"updated_at\":\"2016-01-02T19:51:48.559000682+09:00\",\"status\":\"Running\",\"status_code\":103,\"resources\":{\"containers\":[\"/1.0/containers/test01\"]},\"metadata\":null,\"may_cancel\":false,\"err\":\"\"},\"operation\":\"/1.0/operations/b244aead-bf3f-4e2a-9ad4-0168fa64d45b\"}\n"
103
+ I, [2016-01-02T19:51:53.563774 #22904] INFO -- : Deleting Container...
104
+ "{\"type\":\"async\",\"status\":\"OK\",\"status_code\":100,\"metadata\":{\"id\":\"a423baec-656e-49d3-8ab5-270cf7f11492\",\"class\":\"task\",\"created_at\":\"2016-01-02T19:51:53.577319191+09:00\",\"updated_at\":\"2016-01-02T19:51:53.577319191+09:00\",\"status\":\"Running\",\"status_code\":103,\"resources\":{\"containers\":[\"/1.0/containers/test01\"]},\"metadata\":null,\"may_cancel\":false,\"err\":\"\"},\"operation\":\"/1.0/operations/a423baec-656e-49d3-8ab5-270cf7f11492\"}\n"
105
+ ```
106
+
107
+ ## Development
108
+
109
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
110
+
111
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
112
+
113
+ ## Contributing
114
+
115
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/oreno_lxdapi.
116
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,206 @@
1
+ require "oreno_lxdapi/version"
2
+ require "net_http_unix"
3
+ require "json"
4
+ require "logger"
5
+
6
+ module OrenoLxdapi
7
+ class Client
8
+
9
+ def initialize(uri, image_name, container_name)
10
+ @log = Logger.new(STDOUT)
11
+ @uri = uri
12
+ @image_name = image_name
13
+ @container_name = container_name
14
+ end
15
+
16
+ def client
17
+ NetX::HTTPUnix.new(@uri)
18
+ end
19
+
20
+ def list_containers
21
+ req = Net::HTTP::Get.new("/1.0/containers")
22
+ resp = client.request(req)
23
+ return resp.body
24
+ end
25
+
26
+ def config_container(opts={})
27
+ end
28
+
29
+ def create_container(opts={})
30
+ options = {
31
+ :architecture => 2,
32
+ :profiles => ["default"],
33
+ :ephemeral => true,
34
+ :limits_cpu => "1",
35
+ }
36
+
37
+ options.merge!(opts)
38
+
39
+ req = Net::HTTP::Post.new("/1.0/containers")
40
+ req["Content-Type"] = "application/json"
41
+ payload = {
42
+ "name" => @container_name,
43
+ "architecture" => options[:architecture].to_i,
44
+ "profiles" => options[:profiles],
45
+ "ephemeral" => options[:ephemeral],
46
+ "config" => {
47
+ "limits.cpu" => options[:limits_cpu]
48
+ },
49
+ "source" => {
50
+ "type" => "image",
51
+ "alias" => @image_name
52
+ }
53
+ }
54
+ req.body = payload.to_json
55
+
56
+ resp = client.request(req)
57
+ return resp.body
58
+ end
59
+
60
+ def delete_container
61
+ @log.info("Deleting Container...")
62
+ req = Net::HTTP::Delete.new("/1.0/containers/#{@container_name}")
63
+ resp = client.request(req)
64
+ return resp.body
65
+ end
66
+
67
+ def describe_container
68
+ req = Net::HTTP::Get.new("/1.0/containers/#{@container_name}")
69
+ resp = client.request(req)
70
+ json = JSON.parse(resp.body)
71
+
72
+ if json['metadata']
73
+ return json['metadata']
74
+ else
75
+ @log.warn("Failed to get metadata.")
76
+ end
77
+
78
+ end
79
+
80
+ def check_container_status
81
+ req = Net::HTTP::Get.new("/1.0/containers/#{@container_name}/state")
82
+ resp = client.request(req)
83
+ json = JSON.parse(resp.body)
84
+
85
+ status = ""
86
+ ipv4 = ""
87
+ if json['metadata']
88
+ status = json['metadata']['status']
89
+ unless json['metadata']['ips'] == nil
90
+ json['metadata']['ips'].each { |ip| ipv4 = ip['address'] if ip['interface'] == "eth0"}
91
+ return status, ipv4
92
+ else
93
+ return status
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ def state_container(action, opts={})
100
+ options = {
101
+ :timeout => 30,
102
+ :force => true
103
+ }
104
+
105
+ options.merge!(opts)
106
+
107
+ req = Net::HTTP::Put.new("/1.0/containers/#{@container_name}/state")
108
+ req["Content-Type"] = "application/json"
109
+ payload = {
110
+ "action" => action,
111
+ "timeout" => options[:timeout],
112
+ "force" => options[:force]
113
+ }
114
+ req.body = payload.to_json
115
+ resp = client.request(req)
116
+
117
+ if action == "start"
118
+ loop do
119
+ @log.info("Starting Container...")
120
+ status = check_container_status
121
+ if status.length == 2 && status[1] != ""
122
+ break
123
+ end
124
+
125
+ sleep 3
126
+ end
127
+ return resp.body
128
+ elsif action == "stop"
129
+ @log.info("Stopping Container...")
130
+ return resp.body
131
+ else
132
+ @log.warn("Invalid argument.")
133
+ end
134
+
135
+ end
136
+
137
+ def file_upload(src, dst)
138
+ req = Net::HTTP::Post.new("/1.0/containers/#{@container_name}/files?path=#{dst}")
139
+ req["X-LXD-uid"] = "0"
140
+ req["X-LXD-gid"] = "0"
141
+ req["X-LXD-mode"] = "700"
142
+ req["Content-Type"] = "multipart/form-data"
143
+
144
+ resp = ""
145
+ File.open(src, 'rb') do |f|
146
+ req.body_stream = f
147
+ req["Content-Length"] = f.size
148
+ resp = client.request(req)
149
+ end
150
+
151
+ return resp.body
152
+ end
153
+
154
+ def create_exec(command)
155
+ # commands = command.split(" ")
156
+ # req = Net::HTTP::Post.new("/1.0/containers/#{@container_name}/exec")
157
+ # req["Content-Type"] = "application/json"
158
+ # payload = {
159
+ # "command" => commands,
160
+ # "environment" => {
161
+ # "HOME" => "/root",
162
+ # "TERM" => "screen",
163
+ # "USER" => "root",
164
+ # },
165
+ # "wait-for-websocket" => true,
166
+ # "interactive" => true,
167
+ # }
168
+ # req.body = payload.to_json
169
+ #
170
+ # resp = client.request(req)
171
+ # json = JSON.parse(resp.body)
172
+
173
+ # operation_id = ""
174
+ # secret = ""
175
+
176
+ # if json['metadata']
177
+ # operation_id = json['metadata']['id']
178
+ # unless json['metadata']['metadata'] == nil
179
+ # secret = json['metadata']['metadata']['fds']['0']
180
+ # return operation_id, secret
181
+ # else
182
+ # return operation_id
183
+ # end
184
+ # end
185
+
186
+ end
187
+
188
+ def run_exec(operation_id, secret)
189
+ # run_lxc_exec
190
+ end
191
+
192
+ def run_lxc_exec(command)
193
+ lxc_exec = "lxc exec #{@container_name} -- "
194
+ run_command = lxc_exec + command
195
+ status = system(run_command)
196
+ return status
197
+ end
198
+
199
+ #def wait_operation(operation_id)
200
+ # req = Net::HTTP::Get.new("/1.0/operations/#{operation_id}/wait")
201
+ # resp = client.request(req)
202
+ # return resp.body
203
+ #end
204
+
205
+ end
206
+ end
@@ -0,0 +1,3 @@
1
+ module OrenoLxdapi
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'oreno_lxdapi/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "oreno_lxdapi"
8
+ spec.version = OrenoLxdapi::VERSION
9
+ spec.authors = ["inokappa"]
10
+ spec.email = ["inokara at gmail.com"]
11
+
12
+ spec.summary = %q{oreno}
13
+ spec.description = %q{lxdapi}
14
+ spec.homepage = ""
15
+
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "net_http_unix"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "pry"
28
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oreno_lxdapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - inokappa
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net_http_unix
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: lxdapi
84
+ email:
85
+ - inokara at gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - README.md
95
+ - Rakefile
96
+ - lib/oreno_lxdapi.rb
97
+ - lib/oreno_lxdapi/version.rb
98
+ - oreno_lxdapi.gemspec
99
+ homepage: ''
100
+ licenses: []
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.2.2
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: oreno
122
+ test_files: []