ironfan 5.0.11 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/.gitignore +4 -0
  2. data/.gitmodules +3 -0
  3. data/Gemfile +8 -26
  4. data/Gemfile.lock +38 -41
  5. data/NOTES-REALM.md +172 -0
  6. data/Rakefile +19 -77
  7. data/config/ubuntu12.04-ironfan.erb +7 -0
  8. data/ironfan.gemspec +28 -225
  9. data/lib/chef/cluster_knife.rb +26 -0
  10. data/lib/chef/knife/bootstrap/ubuntu12.04-ironfan.erb +7 -0
  11. data/lib/chef/knife/cluster_bootstrap.rb +1 -3
  12. data/lib/chef/knife/cluster_diff.rb +2 -8
  13. data/lib/chef/knife/cluster_kick.rb +1 -3
  14. data/lib/chef/knife/cluster_kill.rb +1 -2
  15. data/lib/chef/knife/cluster_launch.rb +17 -34
  16. data/lib/chef/knife/cluster_list.rb +6 -5
  17. data/lib/chef/knife/cluster_proxy.rb +1 -3
  18. data/lib/chef/knife/cluster_pry.rb +1 -2
  19. data/lib/chef/knife/cluster_show.rb +6 -7
  20. data/lib/chef/knife/cluster_ssh.rb +10 -8
  21. data/lib/chef/knife/cluster_start.rb +1 -2
  22. data/lib/chef/knife/cluster_stop.rb +1 -2
  23. data/lib/chef/knife/cluster_sync.rb +2 -3
  24. data/lib/chef/knife/ironfan_knife_common.rb +58 -18
  25. data/lib/chef/knife/ironfan_script.rb +0 -3
  26. data/lib/ironfan/broker/computer.rb +14 -11
  27. data/lib/ironfan/broker.rb +17 -12
  28. data/lib/ironfan/cookbook_requirements.rb +155 -0
  29. data/lib/ironfan/dsl/cloud.rb +2 -0
  30. data/lib/ironfan/dsl/cluster.rb +25 -15
  31. data/lib/ironfan/dsl/component.rb +12 -15
  32. data/lib/ironfan/dsl/compute.rb +10 -8
  33. data/lib/ironfan/dsl/ec2.rb +2 -26
  34. data/lib/ironfan/dsl/facet.rb +16 -14
  35. data/lib/ironfan/dsl/openstack.rb +147 -0
  36. data/lib/ironfan/dsl/realm.rb +23 -16
  37. data/lib/ironfan/dsl/security_group.rb +29 -0
  38. data/lib/ironfan/dsl/server.rb +14 -5
  39. data/lib/ironfan/dsl/static.rb +63 -0
  40. data/lib/ironfan/dsl/vsphere.rb +1 -0
  41. data/lib/ironfan/dsl.rb +1 -134
  42. data/lib/ironfan/headers.rb +19 -0
  43. data/lib/ironfan/provider/chef/node.rb +3 -2
  44. data/lib/ironfan/provider/ec2/machine.rb +10 -14
  45. data/lib/ironfan/provider/ec2/security_group.rb +58 -43
  46. data/lib/ironfan/provider/openstack/elastic_ip.rb +96 -0
  47. data/lib/ironfan/provider/openstack/keypair.rb +78 -0
  48. data/lib/ironfan/provider/openstack/machine.rb +371 -0
  49. data/lib/ironfan/provider/openstack/security_group.rb +224 -0
  50. data/lib/ironfan/provider/openstack.rb +69 -0
  51. data/lib/ironfan/provider/static/machine.rb +192 -0
  52. data/lib/ironfan/provider/static.rb +23 -0
  53. data/lib/ironfan/provider.rb +58 -1
  54. data/lib/ironfan/requirements.rb +17 -1
  55. data/lib/ironfan/version.rb +3 -0
  56. data/lib/ironfan.rb +107 -172
  57. data/spec/chef/cluster_bootstrap_spec.rb +2 -7
  58. data/spec/chef/cluster_launch_spec.rb +1 -2
  59. data/spec/fixtures/realms/samurai.rb +26 -0
  60. data/spec/integration/minimal-chef-repo/clusters/.gitkeep +0 -0
  61. data/spec/integration/minimal-chef-repo/config/.gitkeep +0 -0
  62. data/spec/integration/minimal-chef-repo/knife/credentials/.gitignore +1 -0
  63. data/spec/integration/minimal-chef-repo/knife/credentials/certificates/.gitkeep +0 -0
  64. data/spec/integration/minimal-chef-repo/knife/credentials/client_keys/.gitkeep +0 -0
  65. data/spec/integration/minimal-chef-repo/knife/credentials/data_bag_keys/.gitkeep +0 -0
  66. data/spec/integration/minimal-chef-repo/knife/credentials/ec2_certs/.gitkeep +0 -0
  67. data/spec/integration/minimal-chef-repo/knife/credentials/ec2_keys/.gitkeep +0 -0
  68. data/spec/integration/minimal-chef-repo/knife/credentials/ironfantest-validator.pem +27 -0
  69. data/spec/integration/minimal-chef-repo/knife/credentials/ironfantester.pem +27 -0
  70. data/spec/integration/minimal-chef-repo/tasks/.gitkeep +0 -0
  71. data/spec/ironfan/cluster_spec.rb +1 -2
  72. data/spec/ironfan/diff_spec.rb +0 -2
  73. data/spec/ironfan/dsl_spec.rb +6 -3
  74. data/spec/ironfan/ec2/cloud_provider_spec.rb +17 -18
  75. data/spec/ironfan/ec2/elb_spec.rb +44 -41
  76. data/spec/ironfan/ec2/security_group_spec.rb +45 -47
  77. data/spec/ironfan/manifest_spec.rb +0 -1
  78. data/spec/ironfan/plugin_spec.rb +55 -40
  79. data/spec/ironfan/realm_spec.rb +42 -30
  80. data/spec/spec_helper.rb +17 -31
  81. data/spec/{spec_helper → support}/dummy_chef.rb +0 -0
  82. data/spec/{spec_helper → support}/dummy_diff_drawer.rb +0 -0
  83. metadata +78 -155
  84. data/.rspec +0 -2
  85. data/.yardopts +0 -19
  86. data/VERSION +0 -2
  87. data/chefignore +0 -41
  88. data/notes/Future-development-proposals.md +0 -266
  89. data/notes/Home.md +0 -55
  90. data/notes/INSTALL-cloud_setup.md +0 -103
  91. data/notes/INSTALL.md +0 -134
  92. data/notes/Ironfan-Roadmap.md +0 -70
  93. data/notes/Upgrading-to-v4.md +0 -66
  94. data/notes/advanced-superpowers.md +0 -16
  95. data/notes/aws_servers.jpg +0 -0
  96. data/notes/aws_user_key.png +0 -0
  97. data/notes/cookbook-versioning.md +0 -11
  98. data/notes/core_concepts.md +0 -200
  99. data/notes/declaring_volumes.md +0 -3
  100. data/notes/design_notes-aspect_oriented_devops.md +0 -36
  101. data/notes/design_notes-ci_testing.md +0 -169
  102. data/notes/design_notes-cookbook_event_ordering.md +0 -249
  103. data/notes/design_notes-meta_discovery.md +0 -59
  104. data/notes/ec2-pricing_and_capacity.md +0 -75
  105. data/notes/ec2-pricing_and_capacity.numbers +0 -0
  106. data/notes/homebase-layout.txt +0 -102
  107. data/notes/knife-cluster-commands.md +0 -21
  108. data/notes/named-cloud-objects.md +0 -11
  109. data/notes/opscode_org_key.png +0 -0
  110. data/notes/opscode_user_key.png +0 -0
  111. data/notes/philosophy.md +0 -13
  112. data/notes/rake_tasks.md +0 -24
  113. data/notes/renamed-recipes.txt +0 -142
  114. data/notes/silverware.md +0 -85
  115. data/notes/style_guide.md +0 -300
  116. data/notes/tips_and_troubleshooting.md +0 -92
  117. data/notes/walkthrough-hadoop.md +0 -168
  118. data/notes/walkthrough-web.md +0 -166
  119. data/spec/fixtures/gunbai.rb +0 -24
  120. data/spec/test_config.rb +0 -20
  121. data/tasks/chef_config.rake +0 -38
@@ -0,0 +1,224 @@
1
+ module Ironfan
2
+ class Provider
3
+ class OpenStack
4
+
5
+ class SecurityGroup < Ironfan::Provider::Resource
6
+
7
+ WIDE_OPEN = Range.new(1,65535)
8
+
9
+ delegate :_dump, :authorize_group_and_owner, :authorize_port_range,
10
+ :collection, :collection=, :connection, :connection=, :description,
11
+ :description=, :destroy, :group_id, :group_id=, :identity,
12
+ :identity=, :ip_permissions=, :name, :name=,
13
+ :new_record?, :owner_id, :owner_id=, :reload, :requires,
14
+ :requires_one, :revoke_group_and_owner, :revoke_port_range, :save,
15
+ :symbolize_keys, :wait_for, :name,
16
+ :create_security_group_rule,
17
+ :rules,
18
+ :to => :adaptee
19
+
20
+ def self.shared?() true; end
21
+ def self.multiple?() true; end
22
+ def self.resource_type() :security_group; end
23
+
24
+ def self.expected_ids(computer)
25
+ return unless computer.server
26
+ openstack = computer.server.cloud(:openstack)
27
+ server_groups = computer.server.security_groups
28
+ cloud_groups = openstack.security_groups
29
+
30
+ result = []
31
+ [server_groups, cloud_groups].each do |container|
32
+ container.each { |g| result.push(g.name) }
33
+ end
34
+ return result.uniq
35
+ end
36
+
37
+ def ip_permissions
38
+ end
39
+
40
+ def group_id
41
+ @adaptee.id
42
+ end
43
+
44
+ #
45
+ # Discovery
46
+ #
47
+ def self.load!(cluster=nil)
48
+ OpenStack.connection.security_groups.reject { |raw| raw.blank? }.each do |raw|
49
+ remember SecurityGroup.new(:adaptee => raw)
50
+ end
51
+ end
52
+
53
+ def receive_adaptee(obj)
54
+ obj = OpenStack.connection.security_groups.new(obj) if obj.is_a?(Hash)
55
+ super
56
+ end
57
+
58
+ def to_s
59
+ if ip_permissions.present?
60
+ perm_str = ip_permissions.map{|perm|
61
+ "%s:%s-%s (%s | %s)" % [
62
+ perm['ipProtocol'], perm['fromPort'], perm['toPort'],
63
+ perm['groups' ].map{|el| el['groupName'] }.join(','),
64
+ perm['ipRanges'].map{|el| el['cidrIp'] }.join(','),
65
+ ]
66
+ }
67
+ return "<%-15s %-12s %-25s %s>" % [ self.class.handle, group_id, name, perm_str]
68
+ else
69
+ return "<%-15s %-12s %s>" % [ self.class.handle, group_id, name ]
70
+ end
71
+ end
72
+
73
+ #
74
+ # Manipulation
75
+ #
76
+ def self.prepare!(computers)
77
+ # Create any groups that don't yet exist, and ensure any authorizations
78
+ # that are required for those groups
79
+ cluster_name = nil
80
+ groups_to_create = [ ]
81
+ authorizations_to_ensure = [ ]
82
+
83
+ computers.each{|comp| ensure_groups(comp) if OpenStack.applicable(comp) } # Add facet and cluster security groups for the computer
84
+
85
+ # First, deduce the list of all groups to which at least one instance belongs
86
+ # We'll use this later to decide whether to create groups, or authorize access,
87
+ # using a VPC security group or an Openstack security group.
88
+ groups_that_should_exist = [] #computers.map{|comp| expected_ids(comp) }.flatten.compact.sort.uniq
89
+ groups_to_create << groups_that_should_exist
90
+
91
+ computers.select { |computer| OpenStack.applicable computer }.each do |computer|
92
+ cloud = computer.server.cloud(:openstack)
93
+ cluster_name = computer.server.cluster_name
94
+
95
+ # Iterate over all of the security group information, keeping track of
96
+ # any groups that must exist and any authorizations that must be ensured
97
+ [computer.server.security_groups, cloud.security_groups].each do |container|
98
+
99
+ container.values.each do |dsl_group|
100
+
101
+ groups_to_create << dsl_group.name
102
+
103
+ groups_to_create << dsl_group.group_authorized
104
+
105
+ groups_to_create << dsl_group.group_authorized_by
106
+
107
+ authorizations_to_ensure << dsl_group.group_authorized.map do |other_group|
108
+ {
109
+ :grantor => dsl_group.name,
110
+ :grantee => other_group,
111
+ :grantee_type => :group,
112
+ :range => WIDE_OPEN,
113
+ }
114
+ end
115
+
116
+ authorizations_to_ensure << dsl_group.group_authorized_by.map do |other_group|
117
+ {
118
+ :grantor => other_group,
119
+ :grantee => dsl_group.name,
120
+ :grantee_type => :group,
121
+ :range => WIDE_OPEN,
122
+ }
123
+ end
124
+
125
+ authorizations_to_ensure << dsl_group.range_authorizations.map do |range_auth|
126
+ range, cidr, protocol = range_auth
127
+ {
128
+ :grantor => dsl_group.name,
129
+ :grantee => { :cidr_ip => cidr, :ip_protocol => protocol },
130
+ :grantee_type => :cidr,
131
+ :range => range,
132
+ }
133
+ end
134
+ end
135
+ end
136
+ end
137
+ groups_to_create = groups_to_create.flatten.uniq.reject { |group| recall? group.to_s }.sort
138
+ authorizations_to_ensure = authorizations_to_ensure.flatten.uniq.sort { |a,b| a[:grantor] <=> b[:grantor] }
139
+
140
+ Ironfan.step(cluster_name, "creating security groups", :blue) unless groups_to_create.empty?
141
+ groups_to_create.each do |group|
142
+ if group =~ /\//
143
+ Ironfan.step(group, " assuming that owner/group pair #{group} already exists", :blue)
144
+ else
145
+ Ironfan.step(group, " creating #{group} security group", :blue)
146
+ begin
147
+ tokens = group.to_s.split(':')
148
+ group_id = tokens.pop
149
+ OpenStack.connection.create_security_group(group_id,"Ironfan created group #{group_id}")
150
+ rescue Fog::Compute::OpenStack::Error => e # InvalidPermission.Duplicate
151
+ Chef::Log.info("ignoring security group error: #{e}")
152
+ end
153
+ end
154
+ end
155
+
156
+ # Re-load everything so that we have a @@known list of security groups to manipulate
157
+ load! unless groups_to_create.empty?
158
+
159
+ # Now make sure that all required authorizations are present
160
+ Ironfan.step(cluster_name, "ensuring security group permissions", :blue) unless authorizations_to_ensure.empty?
161
+ authorizations_to_ensure.each do |auth|
162
+ grantor_fog = recall(auth[:grantor])
163
+ if :group == auth[:grantee_type]
164
+ if fog_grantee = recall(auth[:grantee])
165
+ options = { :group => fog_grantee.group_id }
166
+ elsif auth[:grantee] =~ /\//
167
+ options = { :group_alias => auth[:grantee] }
168
+ else
169
+ raise "Don't know what to do with authorization grantee #{auth[:grantee]}"
170
+ end
171
+ message = " ensuring access from #{auth[:grantee]} to #{auth[:grantor]}"
172
+ else
173
+ options = auth[:grantee]
174
+ message = " ensuring #{auth[:grantee][:ip_protocol]} access from #{auth[:grantee][:cidr_ip]} to #{auth[:range]}"
175
+ end
176
+ Ironfan.step(auth[:grantor], message, :blue)
177
+ safely_authorize(grantor_fog, auth[:range], options)
178
+ end
179
+ end
180
+
181
+ #
182
+ # Utility
183
+ #
184
+ def self.ensure_groups(computer)
185
+ return unless OpenStack.applicable computer
186
+ # Ensure the security_groups include those for cluster & facet
187
+ # FIXME: This violates the DSL's immutability; it should be
188
+ # something calculated from within the DSL construction
189
+ Ironfan.todo("CODE SMELL: violation of DSL immutability: #{caller}")
190
+ server = computer.server
191
+ c_group = server.security_group(computer.server.cluster_name)
192
+ c_group.authorized_by_group(c_group.name)
193
+ facet_name = "#{computer.server.cluster_name}-#{computer.server.facet_name}"
194
+ server.security_group(facet_name)
195
+ end
196
+
197
+
198
+ # Try an authorization, ignoring duplicates (this is easier than correlating).
199
+ # Do so for both TCP and UDP, unless only one is specified
200
+ def self.safely_authorize(fog_group,range,options)
201
+ if options[:group_alias]
202
+ owner, group = options[:group_alias].split(/\//)
203
+ self.patiently(fog_group.name, Fog::Compute::OpenStack::Error, :ignore => Proc.new { |e| e.message =~ /This rule already exists in group/ }) do
204
+ OpenStack.connection.authorize_security_group_ingress(
205
+ 'GroupName' => fog_group.name,
206
+ 'SourceSecurityGroupName' => group,
207
+ 'SourceSecurityGroupOwnerId' => owner
208
+ )
209
+ end
210
+ elsif options[:ip_protocol]
211
+ self.patiently(fog_group.name, Excon::Errors::HTTPStatusError, :ignore => Proc.new { |e| e.message =~ /This rule already exists in group/ }) do
212
+ fog_group.create_security_group_rule(range.min, range.max, options[:ip_protocol], options[:cidr_ip], options[:group])
213
+ end
214
+ else
215
+ safely_authorize(fog_group,range,options.merge(:ip_protocol => 'tcp'))
216
+ safely_authorize(fog_group,range,options.merge(:ip_protocol => 'udp'))
217
+ safely_authorize(fog_group,Range.new(-1,-1),options.merge(:ip_protocol => 'icmp')) if(range == WIDE_OPEN)
218
+ return
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,69 @@
1
+ module Ironfan
2
+ class Provider
3
+
4
+ class OpenStack < Ironfan::IaasProvider
5
+ self.handle = :openstack
6
+
7
+ def self.resources
8
+ [ Machine, Keypair, SecurityGroup, ElasticIp ]
9
+ end
10
+
11
+ #
12
+ # Utility functions
13
+ #
14
+ def self.connection
15
+ @@connection ||= Fog::Compute.new(self.openstack_credentials.merge({ :provider => 'openstack' }))
16
+ end
17
+
18
+
19
+ #
20
+ # Returns a hash that maps flavor names to flavors
21
+ #
22
+ def self.flavor_hash
23
+ @@flavors ||= self.connection.flavors.inject({}){|h,f| h[f.name]=f; h }
24
+ end
25
+
26
+ #
27
+ # Returns a hash that maps flavor ids to flavors
28
+ #
29
+ def self.flavor_id_hash
30
+ @@flavor_ids ||= self.connection.flavors.inject({}){|h,f| h[f.id]=f; h }
31
+ end
32
+
33
+
34
+ # Ensure that a fog object (machine, volume, etc.) has the proper tags on it
35
+ def self.ensure_tags(tags,fog)
36
+ # openstack does not have tags.
37
+
38
+ #tags.delete_if {|k, v| fog.tags[k] == v.to_s rescue false }
39
+ #return if tags.empty?
40
+
41
+ #Ironfan.step(fog.name,"tagging with #{tags.inspect}", :green)
42
+ #tags.each do |k, v|
43
+ # Chef::Log.debug( "tagging #{fog.name} with #{k} = #{v}" )
44
+ # Ironfan.safely do
45
+ # config = {:key => k, :value => v.to_s, :resource_id => fog.id }
46
+ # connection.tags.create(config)
47
+ # end
48
+ #end
49
+ end
50
+
51
+ def self.applicable(computer)
52
+ computer.server and computer.server.clouds.include?(:openstack)
53
+ end
54
+
55
+ private
56
+
57
+ def self.openstack_credentials
58
+ return {
59
+ :openstack_api_key => Chef::Config[:knife][:openstack_api_key],
60
+ :openstack_username => Chef::Config[:knife][:openstack_username],
61
+ :openstack_auth_url => Chef::Config[:knife][:openstack_auth_url],
62
+ :openstack_tenant => Chef::Config[:knife][:openstack_tenant],
63
+ :openstack_region => Chef::Config[:knife][:openstack_region],
64
+ }
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,192 @@
1
+ module Ironfan
2
+ class Provider
3
+ class Static
4
+ class Machine < Ironfan::IaasProvider::Machine
5
+
6
+ def self.shared?() false; end
7
+ def self.multiple?() false; end
8
+ def self.resource_type() :machine; end
9
+ def self.expected_ids(computer) [computer.server.full_name]; end
10
+
11
+ def name() adaptee.full_name; end
12
+ def tags
13
+ t = {"Name" => @adaptee.name}
14
+ return t.keys.inject({}) {|h,k| h[k]=t[k]; h[k.to_sym]=t[k]; h}
15
+ end
16
+
17
+ def vpc_id
18
+ return nil
19
+ end
20
+
21
+ def created_at
22
+ nil
23
+ end
24
+
25
+ def flavor_id
26
+ return nil
27
+ end
28
+
29
+ def flavor_name
30
+ "nil"
31
+ end
32
+
33
+ def image_id
34
+ "none"
35
+ end
36
+
37
+ def groups ; [] ; end
38
+
39
+ def public_hostname ; adaptee.cloud(:static).public_hostname || public_ip_address ; end
40
+ def public_ip_address ; adaptee.cloud(:static).public_ip || private_ip_address ; end
41
+ def dns_name ; public_ip_address ; end
42
+
43
+ def keypair ; adaptee.cloud(:static).keypair ; end
44
+
45
+ def created?
46
+ false
47
+ end
48
+ def pending?
49
+ false
50
+ end
51
+ def running?
52
+ true
53
+ end
54
+ def stopping?
55
+ false
56
+ end
57
+
58
+ def stopped?
59
+ false
60
+ end
61
+
62
+ def error?
63
+ false
64
+ end
65
+
66
+ def start
67
+ end
68
+
69
+ def stop
70
+ end
71
+
72
+ def perform_after_launch_tasks?
73
+ true
74
+ end
75
+
76
+ def to_display(style,values={})
77
+ # style == :minimal
78
+ values["State"] = "???"
79
+ values["MachineID"] = private_ip_address
80
+ values["Public IP"] = private_ip_address
81
+ values["Private IP"] = public_ip_address
82
+ values["Created On"] = "???"
83
+ return values if style == :minimal
84
+
85
+ # style == :default
86
+ values["Flavor"] = nil
87
+ values["AZ"] = nil
88
+ return values if style == :default
89
+
90
+ # style == :expanded
91
+ values["Image"] = "none"
92
+ #values["Volumes"] = volumes.map(&:id).join(', ')
93
+ values["SSH Key"] = "none"
94
+ values
95
+ end
96
+
97
+ def ssh_key
98
+ keypair = cloud.keypair || computer.server.cluster_name
99
+ end
100
+
101
+ def key_name
102
+ keypair
103
+ end
104
+
105
+ def private_ip_address
106
+ adaptee.cloud(:static).private_ip
107
+ end
108
+
109
+ def availability_zone
110
+ 'none'
111
+ end
112
+
113
+ def destroy
114
+ end
115
+
116
+ def to_s
117
+ "<%-15s %-12s %-25s %-25s %-15s %-15s %-12s %-12s %s:%s>" % [
118
+ self.class.handle, "", created_at, name, private_ip_address, public_ip_address, flavor_name, availability_zone, key_name, groups.join(',') ]
119
+ end
120
+
121
+ #
122
+ # Discovery
123
+ #
124
+ def self.load!(cluster=nil)
125
+ cluster.facets.each do |facet|
126
+ facet.servers.each do |server|
127
+ machine = new(:adaptee => server)
128
+ remember machine
129
+ end
130
+ end
131
+ end
132
+
133
+ # Find active machines that haven't matched, but should have,
134
+ # make sure all bogus machines have a computer to attach to
135
+ # for display purposes
136
+ def self.validate_resources!(computers)
137
+ recall.each_value do |machine|
138
+ next unless machine.users.empty? and machine.name
139
+ if machine.name.match("^#{computers.cluster.name}-")
140
+ machine.bogus << :unexpected_machine
141
+ end
142
+ next unless machine.bogus?
143
+ fake = Ironfan::Broker::Computer.new
144
+ fake[:machine] = machine
145
+ fake.name = machine.name
146
+ machine.users << fake
147
+ computers << fake
148
+ end
149
+ end
150
+
151
+ #
152
+ # Manipulation
153
+ #
154
+ def self.create!(computer)
155
+ nil
156
+ end
157
+
158
+ # @returns [Hash{String, Array}] of 'what you did wrong' => [relevant, info]
159
+ def self.lint(computer)
160
+ cloud = computer.server.cloud(:static)
161
+ info = [computer.name, cloud.inspect]
162
+ errors = {}
163
+ server_errors = computer.server.lint
164
+ errors["No Private IP"] = info if cloud.private_ip.blank?
165
+ errors
166
+ end
167
+
168
+ def self.launch_description(computer)
169
+ nil
170
+ end
171
+
172
+ # An array of hashes with dorky-looking keys, just like Fog wants it.
173
+ def self.block_device_mapping(computer)
174
+ []
175
+ end
176
+
177
+ def self.destroy!(computer)
178
+ return unless computer.machine?
179
+ forget computer.machine.name
180
+ computer.machine.destroy
181
+ computer.machine.reload # show the node as shutting down
182
+ end
183
+
184
+ def self.save!(computer)
185
+ return unless computer.machine?
186
+ return unless computer.created?
187
+ nil
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,23 @@
1
+ module Ironfan
2
+ class Provider
3
+ class Static < Ironfan::IaasProvider
4
+ self.handle = :static
5
+
6
+ def self.resources
7
+ [ Machine ]
8
+ end
9
+
10
+ def self.ensure_tags(tags,fog)
11
+ # Ironfan.safely do
12
+ # config = {:key => k, :value => v.to_s, :resource_id => fog.id }
13
+ # connection.tags.create(config)
14
+ # end
15
+ #end
16
+ end
17
+
18
+ def self.applicable(computer)
19
+ computer.server and computer.server.clouds.include?(:static)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -13,6 +13,8 @@ module Ironfan
13
13
  case obj[:name]
14
14
  when :chef then Chef
15
15
  when :ec2 then Ec2
16
+ when :openstack then OpenStack
17
+ when :static then Static
16
18
  when :vsphere then Vsphere
17
19
  when :virtualbox then VirtualBox
18
20
  when :rds then Rds
@@ -204,7 +206,62 @@ module Ironfan
204
206
  class Machine < Resource
205
207
  # A Machine lives and dies with its Computer
206
208
  def self.shared?() false; end
209
+
210
+ def self.cloud_init_user_data(computer)
211
+ return <<EOF
212
+ #cloud-config
213
+ # The line above is critical - without it cloud-init will not interpret the machine
214
+ # user data as a cloud-init script.
215
+
216
+ # The following logs everything cloud init does to /var/log
217
+ output: {all: '| tee -a /var/log/cloud-init-output.log'}
218
+
219
+ # Set our hostname
220
+ manage_etc_hosts: True
221
+
222
+ cloud_init_modules:
223
+ - bootcmd
224
+ - resizefs
225
+ - set_hostname
226
+ - update_hostname
227
+ - update_etc_hosts
228
+ - write-files
229
+ - ca-certs
230
+ - rsyslog
231
+ - ssh
232
+
233
+ fqdn: #{computer.server.fqdn}
234
+
235
+ bootcmd:
236
+ # note that writefiles is not supported on precise...
237
+ - |
238
+ mkdir -p /etc/chef
239
+ touch /etc/chef/client.pem
240
+ chmod 600 /etc/chef/client.pem
241
+ chown root:root /etc/chef/client.pem
242
+ cat > /etc/chef/client.pem << EOF
243
+ #{computer.private_key.split("\n").map {|l| " "+l}.join("\n")}
244
+ EOF
245
+ domainname #{computer.server.fqdn}
246
+
247
+ chef:
248
+ install_type: "packages"
249
+ force_install: false
250
+ server_url: #{Chef::Config[:chef_server_url]}
251
+ node_name: #{computer.name}
252
+ initial_attributes:
253
+ chef_server: #{Chef::Config[:chef_server_url]}
254
+ node_name: #{computer.name}
255
+ organization: #{Chef::Config[:organization]}
256
+ realm_name: #{computer.server.realm_name}
257
+ cluster_name: #{computer.server.cluster_name}
258
+ facet_name: #{computer.server.facet_name}
259
+ facet_index: #{computer.server.index}
260
+ validation_name: "no-validator"
261
+ validation_key: |
262
+ We don't need no stinking validators.
263
+ EOF
264
+ end
207
265
  end
208
266
  end
209
-
210
267
  end
@@ -1,7 +1,10 @@
1
+ # Built on top of chef
2
+ require 'chef'
3
+
1
4
  # Gorillib core classes
2
5
  require 'gorillib/builder'
6
+ require 'gorillib/diff'
3
7
  require 'gorillib/resolution'
4
-
5
8
  require 'gorillib/nil_check_delegate'
6
9
 
7
10
  # Pre-declaration of class hierarchy
@@ -11,10 +14,12 @@ require 'ironfan/headers'
11
14
  require 'ironfan/plugin/base'
12
15
 
13
16
  # DSL for cluster descriptions
17
+ require 'ironfan/cookbook_requirements'
14
18
  require 'ironfan/dsl'
15
19
  require 'ironfan/builder'
16
20
 
17
21
  require 'ironfan/dsl/component'
22
+ require 'ironfan/dsl/security_group'
18
23
  require 'ironfan/dsl/compute'
19
24
  require 'ironfan/dsl/server'
20
25
  require 'ironfan/dsl/facet'
@@ -26,6 +31,8 @@ require 'ironfan/dsl/volume'
26
31
 
27
32
  require 'ironfan/dsl/cloud'
28
33
  require 'ironfan/dsl/ec2'
34
+ require 'ironfan/dsl/openstack'
35
+ require 'ironfan/dsl/static'
29
36
  require 'ironfan/dsl/vsphere'
30
37
  require 'ironfan/dsl/rds'
31
38
 
@@ -48,6 +55,15 @@ require 'ironfan/provider/ec2/elastic_ip'
48
55
  require 'ironfan/provider/ec2/elastic_load_balancer'
49
56
  require 'ironfan/provider/ec2/iam_server_certificate'
50
57
 
58
+ require 'ironfan/provider/openstack'
59
+ require 'ironfan/provider/openstack/machine'
60
+ require 'ironfan/provider/openstack/keypair'
61
+ require 'ironfan/provider/openstack/security_group'
62
+ require 'ironfan/provider/openstack/elastic_ip'
63
+
64
+ require 'ironfan/provider/static'
65
+ require 'ironfan/provider/static/machine'
66
+
51
67
  require 'ironfan/provider/virtualbox'
52
68
  require 'ironfan/provider/virtualbox/machine'
53
69
 
@@ -0,0 +1,3 @@
1
+ module Ironfan
2
+ VERSION = '6.0.0'
3
+ end