pec 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8c854b8e393a921d53b14b6faa4704c69179e89f
4
- data.tar.gz: b5e10b9145475986f2f59b23fb762bcac456bd1b
3
+ metadata.gz: 8a7355209a3c35e40ac68d514cae1e0ed75e8102
4
+ data.tar.gz: ea45ced7c65397076d2c7496eb5efe44ffa6d41a
5
5
  SHA512:
6
- metadata.gz: fc62df875382a1a9e46f84592212f69ec4c015132aa2804f8b698084b3af401218c6c005df8cf41dc7442bde7cd85910f3c1221dcc394c06f4c2063839fdc009
7
- data.tar.gz: aa06178e8af7c13cb6019ee4db98624f873be9ab1e2368730522ce5942e548348d788162f71d2a1a34be1af2270f2c9b3c2f822d9576df782e01011aeeff040c
6
+ metadata.gz: 3f40e9678fbd05ffeac16fac0ca9eb1832185a38526a188149a473dee6d8e397d1250b1c081a30b687262fb02e7ebab83b02c53dcca3d9b03f7cb4f15daffdb8
7
+ data.tar.gz: 57feae3668f00d475f1b1be8871294caa4fb7ac72ace25a78a9af76e57220cf1dd70dcf58e4aa7e5b5392e20db6c782cf49fd11459c664c44046697d56accc1d
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  /*.yaml
12
12
  *.sample
13
13
  /user_datas
14
+ .ruby-version
data/README.md CHANGED
@@ -37,6 +37,7 @@ _default_: &def
37
37
  tenant: your_tenant
38
38
  image: centos-7.1_chef-12.3_puppet-3.7
39
39
  flavor: m1.small
40
+ availability_zone: nova
40
41
 
41
42
  pyama-test001:
42
43
  <<: *def
@@ -74,8 +75,10 @@ pyama-test002:
74
75
  | flavor | フレーバー名 | ○ | m1.small |
75
76
  | networks | ネットワーク定義 | - | [] |
76
77
  | security_group | セキュリティグループ名 | - | [default,ssh] |
77
- | templates | `user_data`のテンプレート.`./user_data`に配置 | - | [base.yaml,webserver.yaml] |
78
+ | templates | `user_data`のテンプレート `./user_data` に配置 | - | [base.yaml,webserver.yaml] |
78
79
  | user_data | cloud-init記法に準拠 | - | - |
80
+ | availability_zone | アベイラビリティゾーン | - | nova |
81
+
79
82
  * 先頭が_で開始されるインスタンス名はyaml merge記法用途と認識し、スキップします
80
83
 
81
84
  ##### Networks
data/lib/pec.rb CHANGED
@@ -2,42 +2,45 @@ require 'fog'
2
2
  require 'ip'
3
3
  require 'colorator'
4
4
  require "pec/version"
5
- require "pec/query"
6
- require "pec/errors"
7
- require "pec/init"
8
- require "pec/resource"
9
- require "pec/resource/openstack"
10
- require "pec/resource/mock"
11
- require "pec/director"
12
- require "pec/director/helper"
13
- require "pec/director/make_director"
14
- require "pec/director/destroy_director"
15
- require "pec/director/vm_status_director"
5
+ require "pec/logger"
16
6
  require "pec/configure"
17
- require "pec/configure/sample"
18
- require "pec/configure/host"
19
- require "pec/configure/ethernet"
20
- require "pec/configure/user_data"
21
- require "pec/compute/server"
22
- require "pec/compute/flavor"
23
- require "pec/compute/image"
24
- require "pec/compute/tenant"
25
- require "pec/network/security_group"
26
- require "pec/network/port"
27
- require "pec/network/port_state"
28
- require "pec/network/subnet"
7
+ require "pec/director"
8
+ require "pec/builder/server"
9
+ require "pec/builder/port"
10
+ require "pec/builder/user_data"
29
11
  require "pec/cli"
30
12
 
31
13
  module Pec
32
- end
14
+ def self.compute
15
+ @_compute ||= Fog::Compute.new({
16
+ provider: 'openstack'
17
+ })
18
+ @_compute
19
+ end
20
+
21
+ def self.neutron
22
+ @_neutron ||= Fog::Network.new({
23
+ provider: 'openstack'
24
+ })
25
+ @_neutron
26
+ end
27
+
28
+ def self.identity
29
+ @_identity ||= Fog::Identity.new({
30
+ provider: 'openstack'
31
+ })
32
+ @_identity
33
+ end
33
34
 
34
- class ::Hash
35
- def deep_merge(second)
36
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
37
- self.merge(second.to_h, &merger)
38
- end
39
- def deep_merge!(second)
40
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
41
- self.merge!(second.to_h, &merger)
35
+ def self.load_config(file_name=nil)
36
+ file_name ||= 'Pec.yaml'
37
+ @_configure = []
38
+ YAML.load_file(file_name).to_hash.reject {|c| c[0].to_s.match(/^_/)}.each do |host|
39
+ @_configure << Pec::Configure.new(host)
42
40
  end
41
+ end
42
+
43
+ def self.configure
44
+ @_configure
45
+ end
43
46
  end
@@ -0,0 +1,120 @@
1
+ module Pec
2
+ module Builder
3
+ class Port
4
+ attr_reader :user_data
5
+ def build(host)
6
+ ports = []
7
+ @user_data = []
8
+
9
+ host.networks.each do |network|
10
+ validate(network)
11
+ Pec::Logger.notice "port create start : #{network[0]}"
12
+ port = create_port(host, network)
13
+ Pec::Logger.notice "assgin ip : #{port.fixed_ips.first["ip_address"]}"
14
+ ports << port
15
+ @user_data << gen_user_data(network, port)
16
+ end
17
+ {
18
+ nics: ports.map {|port| { port_id: port.id }}
19
+ }
20
+ end
21
+
22
+ def validate(network)
23
+ %w(
24
+ bootproto
25
+ ip_address
26
+ ).each do |k|
27
+ raise "network key #{k} is require" unless network[1][k]
28
+ end
29
+ end
30
+
31
+ def create_port(host, network)
32
+ ip = IP.new(network[1]['ip_address'])
33
+ subnet = Pec.neutron.subnets.find {|s|s.cidr == ip.network.to_s}
34
+ attribute = gen_port_attribute(host, network, subnet, ip)
35
+ Pec.neutron.ports.create(attribute)
36
+ end
37
+
38
+ def gen_port_attribute(host, network, subnet, ip)
39
+ attribute = {
40
+ name: network[0],
41
+ network_id: subnet.network_id
42
+ }
43
+
44
+ attribute.merge!(
45
+ fixed_ip(subnet, ip)
46
+ ) if ip.to_s != subnet.cidr
47
+
48
+ attribute.merge!(
49
+ security_group(host)
50
+ ) if host.security_group
51
+
52
+ attribute.merge!(
53
+ allowed_address_pairs(network)
54
+ ) if network[1]['allowed_address_pairs']
55
+ attribute
56
+ end
57
+
58
+ def gen_user_data(network, port)
59
+ path = network[1]['path'] || "/etc/sysconfig/network-scripts/ifcfg-#{port.name}"
60
+ {
61
+ 'content' => ifcfg_config(network, port),
62
+ 'owner' => "root:root",
63
+ 'path' => path,
64
+ 'permissions' => "0644"
65
+ }
66
+ end
67
+
68
+ def ifcfg_config(network, port)
69
+ base = {
70
+ "name" => port.name,
71
+ "device" => port.name,
72
+ "type" => 'Ethernet',
73
+ "onboot" => 'yes',
74
+ "hwaddr" => port.mac_address
75
+ }
76
+
77
+ base.merge!(
78
+ {
79
+ "netmask" => IP.new(network[1]['ip_address']).netmask.to_s,
80
+ "ipaddr" => port.fixed_ips.first['ip_address'].split("/").first
81
+ }
82
+ ) if network[1]['bootproto'] == "static"
83
+
84
+ # delete options
85
+ %w(allowed_address_pairs ip_address).each {|name| network[1].delete(name)}
86
+
87
+ base.merge!(
88
+ network[1]
89
+ )
90
+
91
+ base.map {|k,v| "#{k.upcase}=#{v}"}.join("\n")
92
+ end
93
+
94
+ #
95
+ # after port options
96
+ #
97
+ def fixed_ip(subnet, ip)
98
+ {
99
+ fixed_ips: [
100
+ { subnet_id: subnet.id, ip_address: ip.to_addr}
101
+ ]
102
+ }
103
+ end
104
+
105
+ def security_group(host)
106
+ ids = host.security_group.map do |name|
107
+ Pec.neutron.security_groups.find {|sg| sg.name == name}.id
108
+ end
109
+ { security_groups: ids }
110
+ end
111
+
112
+ def allowed_address_pairs(network)
113
+ pairs = network[1]['allowed_address_pairs'].map do |pair|
114
+ { ip_address: pair['ip_address'] }
115
+ end
116
+ { allowed_address_pairs: pairs }
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,28 @@
1
+ module Pec
2
+ module Builder
3
+ class Server
4
+ def build(host)
5
+ Pec::Logger.notice "flavor is #{host.flavor}"
6
+ Pec::Logger.notice "image is #{host.image}"
7
+ hash = {
8
+ name: host.name,
9
+ flavor_ref: fetch_flavor(host).id,
10
+ image_ref: fetch_image(host).id
11
+ }
12
+ hash[:availability_zone] = host.availability_zone if host.availability_zone
13
+ hash
14
+ end
15
+
16
+ def self.resource(name)
17
+ define_method("fetch_#{name}", -> (host) {
18
+ r = Pec.compute.send("#{name}s").find {|val|val.name == host.send(name)}
19
+ raise "not fond #{name} #{host.send(name)}" unless r
20
+ r
21
+ })
22
+ end
23
+
24
+ resource 'flavor'
25
+ resource 'image'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module Pec
2
+ module Builder
3
+ class UserData
4
+ def build(host, port_user_data)
5
+ user_data = default(host)
6
+ user_data["write_files"] = port_user_data if port_user_data
7
+ if template = load_template(host)
8
+ user_data.deep_merge!(template)
9
+ end
10
+ { user_data: "#cloud-config\n" + user_data.to_yaml }
11
+ end
12
+
13
+ def load_template(host)
14
+ host.templates.inject({}) do |merge_template, template|
15
+ template.to_s.concat('.yaml') unless template.to_s.match(/.*\.yaml/)
16
+ raise "#{template} not fond!" unless FileTest.exist?("user_data/#{template}")
17
+ merge_template.deep_merge!(YAML.load_file("user_data/#{template}").to_hash)
18
+ end if host.templates
19
+ end
20
+
21
+ def default(host)
22
+ _def = host.user_data || {}
23
+ _def['fqdn'] = host.name if host.user_data && !host.user_data['fqdn']
24
+ _def
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ class ::Hash
31
+ def deep_merge(second)
32
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
33
+ self.merge(second.to_h, &merger)
34
+ end
35
+ def deep_merge!(second)
36
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
37
+ self.merge!(second.to_h, &merger)
38
+ end
39
+ end
@@ -12,19 +12,19 @@ module Pec
12
12
 
13
13
  desc 'up', 'create vm by Pec.yaml'
14
14
  def up(host_name = nil)
15
- Pec::Director.execute("make", host_name)
15
+ Pec::Director.make(host_name)
16
16
  end
17
17
 
18
18
  option :force , type: :boolean, aliases: "-f"
19
19
  desc "destroy", "delete vm"
20
20
  def destroy(host_name = nil)
21
- Pec::Director.execute("destroy", host_name, options)
21
+ Pec::Director.destroy(host_name, options)
22
22
  end
23
23
 
24
24
  desc "status", "vm status"
25
25
  def status(host_name = nil)
26
26
  say("Current machine stasus:", :yellow)
27
- Pec::Director.execute("vm_status", host_name)
27
+ Pec::Director.status(host_name)
28
28
  end
29
29
  end
30
30
  end
@@ -1,36 +1,27 @@
1
- require 'yaml'
2
1
  module Pec
3
2
  class Configure
4
- include Enumerable
5
-
6
- def initialize(file_name)
7
- @configure = []
8
-
9
- if file_name.is_a?(Hash)
10
- hash = file_name
11
- else
12
- hash = YAML.load_file(file_name).to_hash
13
- end
14
-
15
- hash.reject {|c| c[0].to_s.match(/^_/)}.each do |config|
16
-
17
- config[1]['user_data'] ||= {}
18
- config[1]['user_data']['fqdn'] ||= config[0].to_s
3
+ def initialize(config)
4
+ validate(config)
5
+ @_config = config
6
+ end
19
7
 
20
- host = Pec::Configure::Host.new(config)
21
- @configure << host if host
22
- end
23
- rescue Psych::SyntaxError,NoMethodError => e
24
- raise(Pec::Errors::Configure, e)
8
+ def name
9
+ @_config[0]
25
10
  end
26
11
 
27
- def filter_by_host(host_name)
28
- @configure.select {|h| host_name.nil? || host_name == h.name}
12
+ def method_missing(method, *args)
13
+ nil unless @_config[1][method.to_s]
14
+ @_config[1][method.to_s]
29
15
  end
30
16
 
31
- def each
32
- @configure.each do |config|
33
- yield config
17
+ def validate(host)
18
+ %w(
19
+ tenant
20
+ image
21
+ flavor
22
+ networks
23
+ ).each do |k|
24
+ raise "host key #{k} is require" unless host[1][k]
34
25
  end
35
26
  end
36
27
  end
@@ -1,57 +1,116 @@
1
1
  module Pec
2
- class Director
3
- class << self
4
-
5
- def execute(action, host_name, options=nil)
6
- config = Pec::Configure.new("Pec.yaml")
7
- director = assign_director(action, options)
8
- config.filter_by_host(host_name).each do |host|
9
- begin
10
- director.execute!(host) if director.do_it?(host)
11
- rescue Pec::Errors::Error => e
12
- director.err_message(e, host)
13
- rescue Excon::Errors::SocketError => e
14
- err_message(e)
15
- rescue Excon::Errors::Error => e
16
- excon_err_message(e)
17
- end
18
- end if config
19
-
20
- rescue Pec::Errors::Configure => e
21
- config_load_err_message(e)
22
- rescue Pec::Errors::Error => e
23
- err_message(e)
24
- rescue Errno::ENOENT => e
25
- err_message(e)
2
+ class Director
3
+ def self.make(host_name)
4
+ Pec.load_config
5
+ Pec.configure.each do |host|
6
+ next if host_name && host.name != host_name
7
+ Pec::Logger.info "make start #{host.name}"
8
+
9
+ Pec.compute.set_tenant(host.tenant)
10
+ Pec.neutron.set_tenant_patch(host.tenant)
11
+
12
+ port_builder = Pec::Builder::Port.new
13
+ server_builder = Pec::Builder::Server.new
14
+ user_data_builder = Pec::Builder::UserData.new
15
+
16
+ attribute = {}
17
+ attribute.merge!(server_builder.build(host))
18
+ attribute.merge!(port_builder.build(host))
19
+
20
+ if user_data = user_data_builder.build(host, port_builder.user_data)
21
+ attribute.merge!(user_data)
22
+ end
23
+
24
+ Pec::Logger.info "create success! #{host.name}" if Pec.compute.servers.create(attribute)
26
25
  end
27
26
 
28
- def assign_director(action, options)
29
- case
30
- when action == "make"
31
- Pec::Director::MakeDirector.new
32
- when action == "destroy"
33
- Pec::Director::DestroyDirector.new(options)
34
- when action == "vm_status"
35
- Pec::Director::VmStatusDirector.new
36
- else
37
- raise
27
+ rescue Excon::Errors::Error => e
28
+ excon_err_message(e)
29
+ rescue => e
30
+ Pec::Logger.critical(e)
31
+ end
32
+
33
+ def self.destroy(host_name, options)
34
+ Pec.load_config
35
+ Pec.configure.each do |host|
36
+ next if host_name && host.name != host_name
37
+ Pec.compute.set_tenant(host.tenant)
38
+
39
+ server = Pec.compute.servers.find {|s|s.name == host.name}
40
+ unless server
41
+ Pec::Logger.notice "not be created #{host.name}"
42
+ next
43
+ end
44
+
45
+ if options[:force] || Thor.new.yes?("#{host.name}: Are you sure you want to destroy the '#{host.name}' VM? [y/N]")
46
+ Pec::Logger.info "#{host.name} is deleted!" if Pec.compute.servers.destroy(server.id)
38
47
  end
39
48
  end
49
+ rescue Excon::Errors::Error => e
50
+ excon_err_message(e)
51
+ rescue => e
52
+ Pec::Logger.critical(e)
53
+ end
54
+
55
+ def self.status(host_name)
56
+ Pec.load_config
57
+ Pec.configure.each do |host|
58
+ next if host_name && host.name != host_name
59
+ server = Pec.compute.servers.find {|s|s.name == host.name}
60
+ if server
61
+ puts sprintf(" %-35s %-10s %-10s %-10s %-10s %-35s %-48s",
62
+ host.name,
63
+ server.state,
64
+ Pec.identity.tenants.find_by_id(server.tenant_id),
65
+ Pec.compute.flavors.get(server.flavor['id']).name,
66
+ server.availability_zone,
67
+ server.os_ext_srv_attr_host,
68
+ server.addresses.map do |net, ethers|
69
+ ethers.map do |ether|
70
+ ether["addr"]
71
+ end
72
+ end.flatten.join(",")
73
+ )
40
74
 
41
- def err_message(e)
42
- puts e.to_s.magenta
75
+ else
76
+ puts sprintf(" %-35s %-10s",
77
+ host.name,
78
+ "uncreated"
79
+ )
80
+ end
43
81
  end
44
82
 
45
- def config_load_err_message(e)
46
- puts e
47
- puts "can't load configfile".magenta
83
+ rescue Excon::Errors::Error => e
84
+ excon_err_message(e)
85
+ rescue => e
86
+ Pec::Logger.critical(e)
87
+ end
88
+
89
+ def self.excon_err_message(e)
90
+ if e.response
91
+ JSON.parse(e.response[:body]).each { |e,m| Pec::Logger.critical("#{e}:#{m["message"]}") }
92
+ else
93
+ Pec::Logger.critical(e)
48
94
  end
95
+ end
96
+ end
97
+ end
49
98
 
50
- def excon_err_message(e)
51
- if e.response
52
- JSON.parse(e.response[:body]).each { |e,m| puts "#{e}:#{m["message"]}".magenta }
53
- else
54
- puts e
99
+ module Fog
100
+ module Network
101
+ class OpenStack
102
+ class Real
103
+ def set_tenant_patch(tenant)
104
+ @openstack_must_reauthenticate = true
105
+ @openstack_tenant = tenant.to_s
106
+ authenticate
107
+ @path.sub!(/\/$/, '')
108
+ unless @path.match(SUPPORTED_VERSIONS)
109
+ @path = "/" + Fog::OpenStack.get_supported_version(SUPPORTED_VERSIONS,
110
+ @openstack_management_uri,
111
+ @auth_token,
112
+ @connection_options)
113
+ end
55
114
  end
56
115
  end
57
116
  end