pec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a6e5a3923304e41d105e24cf8891ccd93f3bb805
4
+ data.tar.gz: 0552a19993b6d2489129c5f370ca2b6f0e1cf4ed
5
+ SHA512:
6
+ metadata.gz: 312f3f168a0a338878d20fedf851ae4669fec84755da69b5d86b69964c358e962bb74a796bdfed6aea89fa9307811377b0dd0fd483ec3c91c98fc8a0e531dc67
7
+ data.tar.gz: 5377b587b2813d2086864ba6ec3a1f31a9c5cb098f5b2acab4fa8c3c49cf23bc880aec677810178e0fab8f06acbffd6431ba6d41f670db499b1edc4d7287484d
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /vendor
11
+ *.yaml
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pec.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Pec
2
+
3
+ OpenStackにおいて複数サーバの起動や、
4
+ DHCPサーバがない状況でのIP自動採番を実現します。
5
+
6
+ ## インストール方法
7
+
8
+
9
+ $ gem install pec
10
+
11
+ ## 使用方法
12
+ ### コマンド
13
+ 実行ディレクトリに存在するPec.yamlに基づきホストを作成します。
14
+ ホスト名が指定された場合はそのホストのみ作成します。
15
+
16
+ $ pec up <hostname>
17
+
18
+ $ pec destroy <hostname>
19
+
20
+ ### 設定ファイル
21
+ [fog](https://github.com/fog/fog)を利用しているので、fogの設定を行ってください。
22
+
23
+ ```
24
+ % cat ~/.fog
25
+ default:
26
+ openstack_auth_url: "http://your-openstack-endpoint/v2.0/tokens"
27
+ openstack_username: "admin"
28
+ openstack_tenant: "admin"
29
+ openstack_api_key: "admin-no-password"
30
+ ```
31
+
32
+
33
+ `~/Pec.yaml`
34
+ ```
35
+ pyama-test001:
36
+ image: centos-7.1_chef-12.3_puppet-3.7
37
+ flavor: m1.small
38
+ networks:
39
+ eth0:
40
+ bootproto: static
41
+ ip_address: 157.7.190.128/26
42
+ gateway: 157.7.190.129
43
+ dns1: 8.8.8.8
44
+ dns2: 8.8.8.8
45
+ eth1:
46
+ bootproto: static
47
+ ip_address: 10.51.113.0/24
48
+ dns1: 8.8.8.8
49
+ dns2: 8.8.8.8
50
+ user_data:
51
+ hostname: pyama-test001
52
+ fqdn: pyama-test001.ikemen.com
53
+ repo_releasever: 7.1.1503
54
+ pyama-test002:
55
+ image: centos-7.1_chef-12.3_puppet-3.7
56
+ flavor: m1.midium
57
+ networks:
58
+ eth0:
59
+ bootproto: static
60
+ ip_address: 157.7.190.128/26
61
+ gateway: 157.7.190.129
62
+ dns1: 8.8.8.8
63
+ dns2: 8.8.8.8
64
+ eth1:
65
+ bootproto: static
66
+ ip_address: 10.51.113.0/24
67
+ dns1: 8.8.8.8
68
+ dns2: 8.8.8.8
69
+ user_data:
70
+ hostname: pyama-test002
71
+ fqdn: pyama-test002.ikemen.com
72
+ repo_releasever: 7.1.1503
73
+ ```
74
+ `image`,`flavor`は必須項目です。
75
+ `networks`について指定する場合は、`bootproto`,`ip_address`が必須です。`ip_address`は`xxx.xxx.xxx.xxx/yy`の方式を想定しており、ネットワークアドレスが指定された場合、そのサブネットで未使用のアドレスを自動で採番します。
76
+ `user_data`については`nova api`にネットワーク設定を加えて引き渡すため、cloud-init記法に準拠します。
77
+
78
+
79
+ ## Author
80
+ * pyama86
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "pec"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/pec ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pec'
3
+ Pec::CLI.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/exe/pec ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "pec"
data/lib/pec.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'fog'
2
+ require 'ip'
3
+ require "pec/version"
4
+ require "pec/query"
5
+ require "pec/vm_director"
6
+ require "pec/configure"
7
+ require "pec/configure/host"
8
+ require "pec/configure/ethernet"
9
+ require "pec/configure/user_data"
10
+ require "pec/compute/server"
11
+ require "pec/compute/flavor"
12
+ require "pec/compute/image"
13
+ require "pec/compute/security_group"
14
+ require "pec/network/port"
15
+ require "pec/network/subnet"
16
+ require "pec/cli"
17
+
18
+ module Pec
19
+ end
20
+
data/lib/pec/cli.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'pec'
2
+ require 'thor'
3
+ module Pec
4
+ class CLI < Thor
5
+ option :filename, type: :string, aliases: "-f"
6
+ desc 'up', 'create vm by Pec.yaml'
7
+ def up(host_name = nil)
8
+ config = Pec::Configure.new
9
+ config.load("Pec.yaml")
10
+ director = Pec::VmDirector.new
11
+ config.each do |host|
12
+ next if !host_name.nil? && host.name != host_name
13
+ puts "can't create server:#{host.name}" unless director.make(host)
14
+ end if config
15
+ end
16
+ desc "destroy", "delete vm"
17
+ def destroy(name)
18
+ Pec::Compute::Server.new.destroy!(name) if yes?("#{name}: Are you sure you want to destroy the '#{name}' VM? [y/N]")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ module Pec
2
+ class Compute
3
+ class Flavor
4
+ include Query
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Pec
2
+ class Compute
3
+ class Image
4
+ include Query
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Pec
2
+ class Compute
3
+ class Security_Group
4
+ include Query
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,49 @@
1
+ require 'json'
2
+ module Pec
3
+ class Compute
4
+ class Server
5
+ include Query
6
+ def create(name, image_ref, flavor_ref, ports, options)
7
+ if exists?(name)
8
+ puts "skip create server! name:#{name} is exists!"
9
+ return true
10
+ end
11
+
12
+ networks = ports.map do |port|
13
+ if port.used?
14
+ puts "port-id:#{port.id} ip-addr:#{port.ip_address} in used"
15
+ return false
16
+ end
17
+ { net_id: port.network_id, fixed_ip: port.ip_address, port_id: port.id }
18
+ end if ports
19
+
20
+ options.merge!({ 'nics' => networks })
21
+ response = Fog::Compute[:openstack].create_server(name, image_ref, flavor_ref, options)
22
+ if response[:status] == 202
23
+ puts "success create for server_name:#{name}"
24
+ end
25
+ true
26
+ rescue Excon::Errors::Conflict,Excon::Errors::BadRequest => e
27
+ JSON.parse(e.response[:body]).each { |e,m| puts "#{e}:#{m["message"]}" }
28
+ false
29
+ end
30
+
31
+ def exists?(server_name)
32
+ fetch(server_name)
33
+ end
34
+
35
+ def destroy!(server_name)
36
+ server = fetch(server_name)
37
+ unless server
38
+ puts "server_name:#{server_name} is not fond!"
39
+ return
40
+ end
41
+
42
+ response = Fog::Compute[:openstack].delete_server(server["id"]) if server
43
+ if response && response[:status] == 204
44
+ puts "server_name:#{server_name} is deleted!"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,22 @@
1
+ require 'yaml'
2
+ module Pec
3
+ class Configure
4
+ include Enumerable
5
+
6
+ def load(file_name)
7
+ YAML.load_file(file_name).to_hash.each do |config|
8
+ host = Pec::Configure::Host.load(config)
9
+ @configure ||= []
10
+ @configure << host if host
11
+ end
12
+ rescue Psych::SyntaxError => e
13
+ puts e
14
+ end
15
+
16
+ def each
17
+ @configure.each do |config|
18
+ yield config
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ module Pec
2
+ class Configure
3
+ class Ethernet
4
+ attr_reader :name, :bootproto, :ip_address, :options
5
+ def initialize(config)
6
+ @name = config[0];
7
+ @bootprot = config[1]["bootproto"];
8
+ @ip_address = config[1]["ip_address"];
9
+ @options = config[1].select do |k,v|
10
+ { k => v } if k != "bootproto" && k != "ip_address"
11
+ end
12
+ end
13
+
14
+ class << self
15
+ def load(name, config)
16
+ self.new(config) if check_require_key(name, config) && check_network_key(name, config)
17
+ end
18
+
19
+ def check_require_key(name, config)
20
+ err = %w(bootproto ip_address).find {|k| !config[1].key?(k)}
21
+ return true if err.nil?
22
+ puts "skip! #{name}: #{err} is required!"
23
+ false
24
+ end
25
+
26
+ def check_network_key(name, config)
27
+ net = config[1]
28
+ case
29
+ when (net["bootproto"] == "static" && net["ip_address"].nil?)
30
+ puts "skip! #{name}: ip_address is required by bootproto static"
31
+ return false
32
+ when (!net["bootproto"] == "static" && !net["bootproto"] == "dhcp")
33
+ puts "skip! #{name}: bootproto set the value dhcp or static"
34
+ return false
35
+ when (!net["bootproto"] == "static" && !net["bootproto"] == "dhcp")
36
+ puts "skip! #{name}: bootproto set the value dhcp or static"
37
+ return false
38
+ end
39
+ true
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,38 @@
1
+ module Pec
2
+ class Configure
3
+ class Host
4
+ attr_reader :name, :image, :flavor,:security_group, :user_data, :networks
5
+ def initialize(config)
6
+ @name = config[0];
7
+ @image = config[1]["image"];
8
+ @flavor = config[1]["flavor"];
9
+ @security_group = config[1]["security_group"];
10
+ @user_data = config[1]["user_data"];
11
+ end
12
+
13
+ def append_network(network)
14
+ @networks ||= []
15
+ @networks << network
16
+ end
17
+
18
+ class << self
19
+ def load(config)
20
+ host = self.new(config) if check_require_key(config)
21
+ config[1]["networks"].each do |net|
22
+ net_config = Pec::Configure::Ethernet.load(config[0], net)
23
+ return nil unless net_config
24
+ host.append_network(net_config)
25
+ end if host && config[1]["networks"]
26
+ host
27
+ end
28
+
29
+ def check_require_key(config)
30
+ err = %w(image flavor).find {|r| !config[1].key?(r)}
31
+ return true if err.nil?
32
+ puts "skip! #{config[0]}: #{err} is required!"
33
+ false
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ require 'base64'
2
+ module Pec
3
+ class Configure
4
+ class UserData
5
+ class << self
6
+ def make(config, ports)
7
+ user_data = {}
8
+ user_data["write_files"] = make_port_content(config, ports) if ports
9
+ Base64.encode64("#cloud-config\n" + user_data.merge(config.user_data).to_yaml)
10
+ end
11
+
12
+ def make_port_content(config, ports)
13
+ config.networks.map do |ether|
14
+ port_content = {}
15
+ port_content["name"] = ether.name unless ether.options.key?('name')
16
+ port_content["device"] = ether.name unless ether.options.key?('device')
17
+ port_content["type"] = 'Ethernet' unless ether.options.key?('type')
18
+ port_content["onboot"] = "yes" unless ether.options.key?('onboot')
19
+
20
+ _path = "/etc/sysconfig/network-scripts/ifcfg-#{ether.name}" unless ether.options.key?('path')
21
+
22
+ port = ports.find {|p| p.name == ether.name}
23
+
24
+ if port
25
+ port_content["netmask"] = port.netmask
26
+ port_content["hwaddr"] = port.mac_address
27
+ port_content["ipaddr"] = port.ip_address
28
+ end
29
+ port_content.merge!(ether.options)
30
+ {
31
+ 'content' => port_content.map {|k,v| "#{k.upcase}=#{v}"}.join("\n"),
32
+ 'owner' => "root:root",
33
+ 'path' => _path,
34
+ 'permissions' => "0644"
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,78 @@
1
+ require 'json'
2
+ module Pec
3
+ class Network
4
+ class Port
5
+ attr_reader :name, :subnet
6
+ include Query
7
+ def initialize(name, ip_addr, subnet)
8
+ @name = name
9
+ @subnet = subnet
10
+ @config = fetch(ip_addr)
11
+ end
12
+
13
+ def fetch(ip_addr)
14
+ list.find {|p| p["fixed_ips"][0]["ip_address"] == ip_addr }
15
+ end
16
+
17
+ def exists?
18
+ !@config.nil?
19
+ end
20
+
21
+ def used?
22
+ @config && !@config["device_owner"].empty?
23
+ end
24
+
25
+ def id
26
+ @config["id"]
27
+ end
28
+
29
+ def mac_address
30
+ @config["mac_address"]
31
+ end
32
+
33
+ def ip_address
34
+ @config["fixed_ips"][0]["ip_address"]
35
+ end
36
+
37
+ def network_id
38
+ @config["network_id"]
39
+ end
40
+
41
+ def netmask
42
+ IP.new(@config["fixed_ips"][0]["ip_address"]).netmask.to_s
43
+ end
44
+
45
+ def create(ip)
46
+ options = {}
47
+ ## parameter is network address to dhcp
48
+ if ip.to_s != subnet["cidr"]
49
+ options = { fixed_ips: [{ subnet_id: @subnet["id"], ip_address: ip.to_addr}]}
50
+ end
51
+
52
+ res = Fog::Network[:openstack].create_port(@subnet["network_id"], options)
53
+
54
+ @config = res.data[:body]["port"] if res
55
+ @@_list['port'] ||= []
56
+ @@_list['port'] << @config
57
+ true
58
+ rescue Excon::Errors::Conflict => e
59
+ JSON.parse(e.response[:body]).each { |e,m| puts "#{e}:#{m["message"]}" }
60
+ false
61
+ end
62
+
63
+ def delete(port_id)
64
+ Fog::Network[:openstack].delete_port(port_id)
65
+ rescue Excon::Errors::Conflict => e
66
+ JSON.parse(e.response[:body]).each { |e,m| puts "#{e}:#{m["message"]}" }
67
+ false
68
+ end
69
+
70
+ def replace(ip)
71
+ delete(id)
72
+ @@_list['port'] = nil
73
+ create(ip)
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,10 @@
1
+ module Pec
2
+ class Network
3
+ class Subnet
4
+ include Query
5
+ def fetch(cidr)
6
+ list.find {|p| p["cidr"] == cidr }
7
+ end
8
+ end
9
+ end
10
+ end
data/lib/pec/query.rb ADDED
@@ -0,0 +1,31 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+ require 'fog'
3
+ module Pec
4
+ module Query
5
+ @@_list = Hash.new
6
+ def get_adapter
7
+ case
8
+ when self.class.name.include?('Network')
9
+ Fog::Network[:openstack]
10
+ when self.class.name.include?('Compute')
11
+ Fog::Compute[:openstack]
12
+ else
13
+ raise
14
+ end
15
+ end
16
+
17
+ def list
18
+ name = self.class.name.demodulize.downcase+"s"
19
+ @@_list[name] || get_adapter.send("list_#{name}").data[:body][name]
20
+ end
21
+
22
+ def fetch(name)
23
+ list.find {|s| s["name"] == name}
24
+ end
25
+
26
+ def get_ref(name)
27
+ response = fetch(name)
28
+ response["links"][0]["href"]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Pec
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,67 @@
1
+ module Pec
2
+ class VmDirector
3
+ def initialize
4
+ @subnet = Pec::Network::Subnet.new
5
+ @flavor = Pec::Compute::Flavor.new
6
+ @image = Pec::Compute::Image.new
7
+ @security_group = Pec::Compute::Security_Group.new
8
+ @compute = Pec::Compute::Server.new
9
+ end
10
+
11
+ def make(config)
12
+ ports = get_ports(config)
13
+ flavor_ref = get_flavor(config.flavor)
14
+ image_ref = get_image(config.image)
15
+ return false unless flavor_ref && image_ref
16
+ options = {
17
+ "user_data" => Pec::Configure::UserData.make(config, ports),
18
+ "security_groups" => config.security_group
19
+ }
20
+
21
+ @compute.create(config.name, image_ref, flavor_ref, ports, options)
22
+ end
23
+
24
+ def get_ports(config)
25
+ config.networks.map do |ether|
26
+ ip = IP.new(ether.ip_address)
27
+ _subnet = get_subnet(ip)
28
+ return false unless _subnet
29
+
30
+ _port = Pec::Network::Port.new(ether.name, ip.to_addr, _subnet)
31
+
32
+ res = case
33
+ when _port.exists? && !_port.used?
34
+ _port.replace(ip)
35
+ when !_port.exists?
36
+ _port.create(ip)
37
+ when _port.used?
38
+ false
39
+ end
40
+
41
+ unless res
42
+ puts "ip addess:#{ip.to_addr} can't create port!"
43
+ return false
44
+ end
45
+ _port
46
+ end if config.networks
47
+ end
48
+
49
+ def get_subnet(ip)
50
+ _subnet = @subnet.fetch(ip.network.to_s)
51
+ puts "ip addess:#{ip.to_addr} subnet not fond!" if _subnet.nil?
52
+ _subnet
53
+ end
54
+
55
+ def get_flavor(name)
56
+ flavor_ref = @flavor.get_ref(name)
57
+ puts "flavor:#{name} not fond!" if flavor_ref.nil?
58
+ flavor_ref
59
+ end
60
+
61
+ def get_image(name)
62
+ image_ref = @image.get_ref(name)
63
+ puts "image:#{name} not fond!" if image_ref.nil?
64
+ image_ref
65
+ end
66
+ end
67
+ end
data/pec.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pec"
8
+ spec.version = Pec::VERSION
9
+ spec.authors = ["kazuhiko yamashita"]
10
+ spec.email = ["pyama@pepabo.com"]
11
+
12
+ spec.summary = %q{openstack vm booter.}
13
+ spec.description = %q{openstac vm booter.}
14
+ spec.homepage = "http://ten-snapon.com"
15
+ spec.license = "MIT"
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
+ spec.add_dependency 'fog'
22
+ spec.add_dependency 'thor'
23
+ spec.add_dependency 'ruby-ip'
24
+ spec.add_dependency 'activesupport'
25
+ spec.add_development_dependency "bundler", "~> 1.9"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - kazuhiko yamashita
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-06-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fog
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: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-ip
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
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: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.9'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ description: openstac vm booter.
98
+ email:
99
+ - pyama@pepabo.com
100
+ executables:
101
+ - pec
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - README.md
109
+ - Rakefile
110
+ - bin/console
111
+ - bin/pec
112
+ - bin/setup
113
+ - exe/pec
114
+ - lib/pec.rb
115
+ - lib/pec/cli.rb
116
+ - lib/pec/compute/flavor.rb
117
+ - lib/pec/compute/image.rb
118
+ - lib/pec/compute/security_group.rb
119
+ - lib/pec/compute/server.rb
120
+ - lib/pec/configure.rb
121
+ - lib/pec/configure/ethernet.rb
122
+ - lib/pec/configure/host.rb
123
+ - lib/pec/configure/user_data.rb
124
+ - lib/pec/network/port.rb
125
+ - lib/pec/network/subnet.rb
126
+ - lib/pec/query.rb
127
+ - lib/pec/version.rb
128
+ - lib/pec/vm_director.rb
129
+ - pec.gemspec
130
+ homepage: http://ten-snapon.com
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.4.6
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: openstack vm booter.
154
+ test_files: []