itamae-mitsurin 0.9 → 0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,123 +1,88 @@
1
1
  require 'json'
2
2
  require 'highline'
3
+ require 'itamae-mitsurin/mitsurin/task_base'
3
4
  include Rake::DSL if defined? Rake::DSL
4
5
 
5
6
  module Itamae
6
7
  module Mitsurin
7
8
  class ServerspecTask
8
9
 
9
- class << self
10
+ TaskBase = ItamaeMitsurin::Mitsurin::TaskBase
10
11
 
11
- task :spec => 'spec:all'
12
- task :default => :spec
12
+ namespace :spec do
13
+ all = []
14
+ Dir.glob("tmp-nodes/**/*.json").each do |node_file|
13
15
 
14
- def self.get_roles(node_file)
15
- roles = []
16
- JSON.parse(File.read(node_file))['run_list'].each do |role|
17
- roles << role.gsub(/role\[(.+)\]/, '\1') if /role\[(.+)\]/ === role
18
- end
19
- roles
20
- end
16
+ file_name = File.basename(node_file, '.json')
17
+ node_attr = JSON.parse(File.read(node_file), symbolize_names: true)
21
18
 
22
- def self.get_recipes(role)
23
- recipes = []
24
- JSON.parse(File.read("roles/#{role}.json"))['run_list'].each do |recipe|
25
- if /recipe\[(.+)::(.+)\]/ === recipe
26
- recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
27
- else
28
- recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil}
29
- end
30
- end
31
- recipes
32
- end
19
+ desc "Spec to #{file_name}"
20
+ task node_attr[:environments][:hostname].split(".")[0] do
33
21
 
34
- def self.get_node_recipes(node_file)
35
- recipes = []
36
- JSON.parse(File.read(node_file))['run_list'].each do |recipe|
37
- if /recipe\[(.+)::(.+)\]/ === recipe
38
- recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
39
- else
40
- recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil} unless /role\[(.+)\]/ === recipe
22
+ begin
23
+ recipes = []
24
+ TaskBase.get_roles(node_file).each do |role|
25
+ recipes << TaskBase.get_recipes(role)
41
26
  end
42
- end
43
- recipes
44
- end
45
-
46
- hl = HighLine.new
47
-
48
- namespace :spec do
49
- all = []
50
- Dir.glob("tmp-nodes/**/*.json").each do |node_file|
51
-
52
- file_name = File.basename(node_file, '.json')
53
- node_attr = JSON.parse(File.read(node_file), symbolize_names: true)
54
-
55
- desc "Spec to #{file_name}"
56
- task node_attr[:environments][:hostname].split(".")[0] do
57
-
58
- begin
59
- recipes = []
60
- get_roles(node_file).each do |role|
61
- recipes << get_recipes(role)
62
- end
63
- get_node_recipes(node_file).each do |recipe|
64
- recipes << recipe
65
- end
66
- rescue Exception => e
67
- puts e.class.to_s + ", " + e.backtrace[0].to_s
68
- puts "nodefile or role error, nodefile:#{node_file} reason:#{e.message}"
69
- exit 1
70
- else
71
- recipes << {'_base' => nil}
72
- recipes.flatten!
27
+ TaskBase.get_node_recipes(node_file).each do |recipe|
28
+ recipes << recipe
73
29
  end
30
+ rescue Exception => e
31
+ puts e.class.to_s + ", " + e.backtrace[0].to_s
32
+ puts "nodefile or role error, nodefile:#{node_file} reason:#{e.message}"
33
+ exit 1
34
+ else
35
+ recipes << {'_base' => nil}
36
+ recipes.flatten!
37
+ end
74
38
 
75
- node_name = node_attr[:environments][:hostname]
76
- ssh_user = node_attr[:environments][:ssh_user]
77
- ssh_password = node_attr[:environments][:ssh_password]
78
- sudo_password = node_attr[:environments][:sudo_password]
79
- ssh_port = node_attr[:environments][:ssh_port]
80
- ssh_key = node_attr[:environments][:ssh_key]
39
+ node_name = node_attr[:environments][:hostname]
40
+ ssh_user = node_attr[:environments][:ssh_user]
41
+ ssh_password = node_attr[:environments][:ssh_password]
42
+ sudo_password = node_attr[:environments][:sudo_password]
43
+ ssh_port = node_attr[:environments][:ssh_port]
44
+ ssh_key = node_attr[:environments][:ssh_key]
81
45
 
82
- node_short = node_name.split(".")[0]
46
+ node_short = node_name.split(".")[0]
83
47
  all << node_short
84
48
 
85
49
  desc "Run spec to #{file_name}"
86
- ENV['TARGET_HOST'] = node_name
87
- ENV['NODE_FILE'] = node_file
88
- ENV['SSH_PASSWORD'] = ssh_password
89
- ENV['SUDO_PASSWORD'] = sudo_password
90
- ENV['SSH_KEY'] = "keys/#{ssh_key}"
91
- ENV['SSH_PORT'] = ssh_port
92
- ENV['SSH_USER'] = ssh_user
93
-
94
- specs = "bundle exec rspec"
95
-
96
- # recipe load to_spec
97
- spec_pattern = []
98
- recipes.each do |spec_h|
99
- if spec_h["#{spec_h.keys.join}"].nil?
100
- spec_pattern <<
101
- " #{Dir.glob("site-cookbooks/**/#{spec_h.keys.join}/spec/default_spec.rb").join}"
102
- else
103
- spec_pattern <<
104
- " #{Dir.glob("site-cookbooks/**/#{spec_h.keys.join}/spec/#{spec_h["#{spec_h.keys.join}"]}_spec.rb").join}"
105
- end
50
+ ENV['TARGET_HOST'] = node_name
51
+ ENV['NODE_FILE'] = node_file
52
+ ENV['SSH_PASSWORD'] = ssh_password
53
+ ENV['SUDO_PASSWORD'] = sudo_password
54
+ ENV['SSH_KEY'] = "keys/#{ssh_key}"
55
+ ENV['SSH_PORT'] = ssh_port
56
+ ENV['SSH_USER'] = ssh_user
57
+
58
+ specs = "bundle exec rspec"
59
+
60
+ # recipe load to_spec
61
+ spec_pattern = []
62
+ recipes.each do |spec_h|
63
+ if spec_h["#{spec_h.keys.join}"].nil?
64
+ spec_pattern <<
65
+ " #{Dir.glob("site-cookbooks/**/#{spec_h.keys.join}/spec/default_spec.rb").join}"
66
+ else
67
+ spec_pattern <<
68
+ " #{Dir.glob("site-cookbooks/**/#{spec_h.keys.join}/spec/#{spec_h["#{spec_h.keys.join}"]}_spec.rb").join}"
106
69
  end
107
- spec_pattern.sort_by! {|item| File.dirname(item)}
108
- specs << spec_pattern.join
109
- run_list_noti = []
110
- spec_pattern.each {|c_spec| run_list_noti << c_spec.split("/") [2]}
111
- puts hl.color(%!Run Serverspec to \"#{node_name}\"!, :red)
112
- puts hl.color(%!Run List to \"#{run_list_noti.uniq.join(", ")}\"!, :green)
113
- st = system specs
114
- exit 1 unless st
115
70
  end
116
- task :all => all
117
- task :default => :all
71
+
72
+ spec_pattern.sort_by! {|item| File.dirname(item)}
73
+ specs << spec_pattern.join
74
+ run_list_noti = []
75
+ spec_pattern.each {|c_spec| run_list_noti << c_spec.split("/") [2]}
76
+ puts TaskBase.hl.color(%!Run Serverspec to \"#{node_name}\"!, :red)
77
+ puts TaskBase.hl.color(%!Run List to \"#{run_list_noti.uniq.join(", ")}\"!, :green)
78
+ st = system specs
79
+ exit 1 unless st
118
80
  end
81
+ task :all => all
82
+ task :default => :all
119
83
  end
120
84
  end
85
+
121
86
  end
122
87
  end
123
88
  end
@@ -0,0 +1,72 @@
1
+
2
+ module ItamaeMitsurin
3
+ module Mitsurin
4
+ module TaskBase
5
+
6
+ class << self
7
+ class ::Hash
8
+ def deep_merge(other)
9
+ merger = lambda {|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2}
10
+ self.merge(other, &merger)
11
+ end
12
+
13
+ def deep_merge!(other)
14
+ merger = lambda {|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2}
15
+ self.merge!(other, &merger)
16
+ end
17
+ end
18
+
19
+ def get_roles(node_file)
20
+ roles = []
21
+ JSON.parse(File.read(node_file))['run_list'].each do |role|
22
+ roles << role.gsub(/role\[(.+)\]/, '\1') if /role\[(.+)\]/ === role
23
+ end
24
+ roles
25
+ end
26
+
27
+ def get_recipes(role)
28
+ recipes = []
29
+ JSON.parse(File.read("roles/#{role}.json"))['run_list'].each do |recipe|
30
+ if /recipe\[(.+)::(.+)\]/ === recipe
31
+ recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
32
+ else
33
+ recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil}
34
+ end
35
+ end
36
+ recipes
37
+ end
38
+
39
+ def get_node_recipes(node_file)
40
+ recipes = []
41
+ JSON.parse(File.read(node_file))['run_list'].each do |recipe|
42
+ if /recipe\[(.+)::(.+)\]/ === recipe
43
+ recipes << {recipe.gsub(/recipe\[(.+)::(.+)\]/, '\1') => recipe.gsub(/recipe\[(.+)::(.+)\]/, '\2')}
44
+ else
45
+ recipes << {recipe.gsub(/recipe\[(.+)\]/, '\1') => nil} unless /role\[(.+)\]/ === recipe
46
+ end
47
+ end
48
+ recipes
49
+ end
50
+
51
+ def jq(*objs)
52
+ par = nil
53
+ objs.each {|obj| par = JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)}
54
+ return par
55
+ end
56
+
57
+ def write_json(filename)
58
+ File.open "tmp-nodes/#{filename}.json", 'w' do |f|
59
+ f.flock File::LOCK_EX
60
+ yield f
61
+ f.flock File::LOCK_UN
62
+ end
63
+ end
64
+
65
+ def hl
66
+ HighLine.new
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -19,6 +19,7 @@ require 'itamae-mitsurin/resource/gem_package'
19
19
  require 'itamae-mitsurin/resource/aws_ebs_volume'
20
20
  require 'itamae-mitsurin/resource/aws_route53_rrset'
21
21
  require 'itamae-mitsurin/resource/aws_route53_rrset_alias'
22
+ require 'itamae-mitsurin/resource/aws_ec2_instance'
22
23
 
23
24
  module ItamaeMitsurin
24
25
  module Resource
@@ -2,92 +2,85 @@ require 'itamae-mitsurin'
2
2
  require 'itamae-mitsurin/mitsurin'
3
3
 
4
4
  module ItamaeMitsurin
5
- module Resource
6
- class AwsEbsVolume < Base
7
- define_attribute :action, default: :create
8
- define_attribute :name, type: String, default_name: true
9
- define_attribute :region, type: String
10
- define_attribute :availability_zone, type: String
11
- define_attribute :device, type: String
12
- define_attribute :instance_id, type: String
13
- define_attribute :volume_type, type: String
14
- define_attribute :size, type: Integer
5
+ module Resource
6
+ class AwsEbsVolume < Base
15
7
 
16
- def action_create(options)
17
- ec2 = ::Aws::EC2::Client.new(region: attributes.region)
18
- volumes = ec2.describe_volumes(
8
+ define_attribute :action, default: :create
9
+ define_attribute :name, type: String, default_name: true
10
+ define_attribute :region, type: String
11
+ define_attribute :availability_zone, type: String
12
+ define_attribute :device, type: String
13
+ define_attribute :instance_id, type: String
14
+ define_attribute :volume_type, type: String
15
+ define_attribute :size, type: Integer
16
+
17
+ def action_create(options)
18
+ ec2 = ::Aws::EC2::Client.new(region: attributes.region)
19
+ volumes = ec2.describe_volumes({
20
+ filters: [
19
21
  {
20
- filters: [
21
- {
22
- name: 'tag:Name',
23
- values: [ attributes.name ],
24
- },
25
- ],
26
- }
27
- ).volumes
22
+ name: 'tag:Name',
23
+ values: [ attributes.name ],
24
+ },
25
+ ],
26
+ }).volumes
28
27
 
29
- if volumes.empty?
30
- @volume = ec2.create_volume(
31
- size: attributes[:size], # attributes.size returns the size of attributes hash
32
- availability_zone: attributes.availability_zone,
33
- volume_type: attributes.volume_type,
34
- )
35
- ec2.wait_until(:volume_available, volume_ids: [ @volume.volume_id ])
28
+ if volumes.empty?
29
+ @volume = ec2.create_volume(
30
+ size: attributes[:size], # attributes.size returns the size of attributes hash
31
+ availability_zone: attributes.availability_zone,
32
+ volume_type: attributes.volume_type,
33
+ )
34
+ ec2.wait_until(:volume_available, volume_ids: [ @volume.volume_id ])
36
35
 
37
- ec2.create_tags(
36
+ ec2.create_tags({
37
+ resources: [ @volume.volume_id ],
38
+ tags: [
38
39
  {
39
- resources: [ @volume.volume_id ],
40
- tags: [
41
- {
42
- key: 'Name',
43
- value: attributes.name,
44
- },
45
- ],
46
- }
47
- )
48
-
49
- ItamaeMitsurin.logger.color(:green) do
50
- ItamaeMitsurin.info "create volume compleated!"
51
- end
52
- updated!
53
- else
54
- @volume = volumes[0]
55
- end
40
+ key: 'Name',
41
+ value: attributes.name,
42
+ },
43
+ ],
44
+ })
56
45
 
46
+ ItamaeMitsurin.logger.color(:green) do
47
+ ItamaeMitsurin.info "create volume compleated!"
48
+ end
49
+ updated!
50
+ else
51
+ @volume = volumes[0]
57
52
  end
53
+ end
58
54
 
59
- def action_attach(options)
60
- ec2 = ::Aws::EC2::Client.new(region: attributes.region)
61
- volumes = ec2.describe_volumes(
55
+ def action_attach(options)
56
+ ec2 = ::Aws::EC2::Client.new(region: attributes.region)
57
+ volumes = ec2.describe_volumes({
58
+ filters: [
62
59
  {
63
- filters: [
64
- {
65
- name: 'tag:Name',
66
- values: [ attributes.name ],
67
- },
68
- ],
69
- }
70
- ).volumes
71
-
72
- unless volumes.empty?
73
- @volume = ec2.attach_volume({
74
- volume_id: @volume.volume_id,
75
- instance_id: attributes.instance_id,
76
- device: attributes.device
77
- })
78
- ec2.wait_until(:volume_in_use, volume_ids: [ @volume.volume_id ])
60
+ name: 'tag:Name',
61
+ values: [ attributes.name ],
62
+ },
63
+ ],
64
+ }).volumes
79
65
 
66
+ unless volumes.empty?
67
+ @volume = ec2.attach_volume({
68
+ volume_id: @volume.volume_id,
69
+ instance_id: attributes.instance_id,
70
+ device: attributes.device
71
+ })
72
+ ec2.wait_until(:volume_in_use, volume_ids: [ @volume.volume_id ])
80
73
 
81
- ItamaeMitsurin.logger.color(:green) do
82
- ItamaeMitsurin.info "attach volume compleated!"
83
- end
84
- updated!
85
- else
86
- @volume = volumes[0]
87
- end
88
74
 
75
+ ItamaeMitsurin.logger.color(:green) do
76
+ ItamaeMitsurin.info "attach volume compleated!"
77
+ end
78
+ updated!
79
+ else
80
+ @volume = volumes[0]
89
81
  end
90
82
  end
91
83
  end
84
+ end
92
85
  end
93
86
 
@@ -5,12 +5,12 @@ module ItamaeMitsurin
5
5
  module Resource
6
6
  class AwsEc2Instance < Base
7
7
 
8
- define_attribute :region, type: String
8
+ define_attribute :region, type: String, required: true
9
9
  define_attribute :action, default: :create
10
10
  define_attribute :dry_run, type: [TrueClass, FalseClass], default_name: false
11
11
  define_attribute :name, type: String, default_name: true
12
12
  define_attribute :image_id, type: String, required: true
13
- define_attribute :key_name, type: String, required: true
13
+ define_attribute :key_name, type: String
14
14
  define_attribute :security_group_ids, type: Array
15
15
  define_attribute :user_data, type: String
16
16
  define_attribute :instance_type, type: String, required: true
@@ -18,11 +18,11 @@ module ItamaeMitsurin
18
18
  define_attribute :ramdisk_id, type: String
19
19
  define_attribute :device_name, type: String
20
20
  define_attribute :snapshot_id, type: String
21
- define_attribute :volume_size, type: Integer
21
+ define_attribute :volume_size, type: Integer, required: true
22
22
  define_attribute :delete_on_termination, type: [TrueClass, FalseClass], default: true
23
23
  define_attribute :volume_type, type: String, default: "gp2"
24
24
  define_attribute :iops, type: Integer
25
- define_attribute :encrypted, type: [TrueClass, FalseClass]
25
+ define_attribute :encrypted, type: TrueClass
26
26
  define_attribute :monitoring, type: [TrueClass, FalseClass], default: false
27
27
  define_attribute :subnet_id, type: String
28
28
  define_attribute :disable_api_termination, type: [TrueClass, FalseClass], default: false
@@ -32,7 +32,7 @@ module ItamaeMitsurin
32
32
  define_attribute :additional_info, type: String
33
33
  define_attribute :network_interface_id, type: String
34
34
  define_attribute :device_index, type: String
35
- define_attribute :subnet_id, type: String
35
+ define_attribute :subnet_id, type: String, required: true
36
36
  define_attribute :private_ip_address, type: String
37
37
  define_attribute :groups, type: Array
38
38
  define_attribute :private_ip_address, type: String