| 
									
										
										
										
											2015-08-04 09:56:03 +03:00
										 |  |  |  | require "exceptions/conflict_exception" | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | require "providers/base_provider" | 
					
						
							| 
									
										
										
										
											2015-10-26 12:04:01 +03:00
										 |  |  |  | require "db/mongo/models/provider_accounts/ec2_provider_account" | 
					
						
							| 
									
										
										
										
											2015-10-26 17:14:48 +03:00
										 |  |  |  | require_relative "ec2_accounts_factory" | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  | module Provider | 
					
						
							|  |  |  |  |   # Provider for Amazon EC2 | 
					
						
							|  |  |  |  |   class Ec2 < BaseProvider | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     PROVIDER = "ec2" | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     attr_accessor :availability_zone | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def initialize config | 
					
						
							|  |  |  |  |       self.certificate_path = config[:aws_certificate] | 
					
						
							|  |  |  |  |       self.ssh_key = config[:aws_ssh_key] | 
					
						
							| 
									
										
										
										
											2015-08-07 11:36:50 +03:00
										 |  |  |  |       options = { | 
					
						
							| 
									
										
										
										
											2015-12-07 14:14:10 +03:00
										 |  |  |  |         :provider => "aws" | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-12-07 14:14:10 +03:00
										 |  |  |  |       if config[:aws_use_iam_profile] | 
					
						
							|  |  |  |  |         options[:use_iam_profile] = true | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         options[:aws_access_key_id] = config[:aws_access_key_id] | 
					
						
							|  |  |  |  |         options[:aws_secret_access_key] = config[:aws_secret_access_key] | 
					
						
							|  |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-08-07 12:03:01 +03:00
										 |  |  |  |       if config[:aws_proxy] and config[:aws_no_proxy] | 
					
						
							|  |  |  |  |         options[:connection_options] = { | 
					
						
							|  |  |  |  |           :proxy => config[:aws_proxy], | 
					
						
							|  |  |  |  |           :no_proxy => config[:no_proxy] | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-08-07 11:36:50 +03:00
										 |  |  |  |       self.connection_options = options | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       self.availability_zone = config[:aws_availability_zone] || "us-east-1a" | 
					
						
							| 
									
										
										
										
											2014-11-20 15:08:42 +03:00
										 |  |  |  |       self.run_list = config[:aws_integration_run_list] || [] | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def configured? | 
					
						
							|  |  |  |  |       o = self.connection_options | 
					
						
							|  |  |  |  |       super and !(empty_param?(o[:aws_access_key_id]) or empty_param?(o[:aws_secret_access_key])) | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def name | 
					
						
							|  |  |  |  |       PROVIDER | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def flavors | 
					
						
							|  |  |  |  |       self.compute.flavors.all.map do |f| | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           "id" => f.id, | 
					
						
							|  |  |  |  |           "cores" => f.cores, | 
					
						
							|  |  |  |  |           "disk" => f.disk, | 
					
						
							|  |  |  |  |           "name" => f.name, | 
					
						
							|  |  |  |  |           "ram" => f.ram | 
					
						
							|  |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 12:14:02 +03:00
										 |  |  |  |     def groups filters={} | 
					
						
							| 
									
										
										
										
											2016-01-14 14:17:19 +03:00
										 |  |  |  |       g = self.compute.describe_security_groups(filters || {}) | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       convert_groups(g.body["securityGroupInfo"]) | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def images filters | 
					
						
							|  |  |  |  |       self.compute.describe_images({"image-id" => filters}).body["imagesSet"].map do |i| | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           "id" => i["imageId"], | 
					
						
							|  |  |  |  |           "name" => i["name"], | 
					
						
							|  |  |  |  |           "status" => i["imageState"] | 
					
						
							|  |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 12:14:02 +03:00
										 |  |  |  |     def networks filters={} | 
					
						
							|  |  |  |  |       self.compute.describe_subnets(filters).body["subnetSet"].select{|n| n["state"] == "available"}.map do |n| | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |           "cidr" => n["cidrBlock"], | 
					
						
							|  |  |  |  |           "vpcId" => n["vpcId"], | 
					
						
							|  |  |  |  |           "subnetId" => n["subnetId"], | 
					
						
							|  |  |  |  |           "name" => n["subnetId"], | 
					
						
							|  |  |  |  |           "zone" => n["availabilityZone"] | 
					
						
							|  |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def servers | 
					
						
							|  |  |  |  |       list = self.compute.describe_instances.body["reservationSet"] | 
					
						
							| 
									
										
										
										
											2015-10-28 14:16:56 +03:00
										 |  |  |  |       list.select{|l| l["instancesSet"][0]["instanceState"]["name"].to_s == "running"}.map do |server| | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |         convert_server server["instancesSet"][0] | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def server id | 
					
						
							|  |  |  |  |       list = self.compute.describe_instances('instance-id' => [id]).body["reservationSet"] | 
					
						
							|  |  |  |  |       convert_server list[0]["instancesSet"][0] | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-05 17:38:32 +03:00
										 |  |  |  |     def create_server s, image, flavor, subnets, groups, out, options={} | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       out << "Creating server for project '#{s.project} - #{s.deploy_env}'\n" | 
					
						
							|  |  |  |  |       options = { | 
					
						
							| 
									
										
										
										
											2015-08-05 14:05:14 +03:00
										 |  |  |  |         "InstanceType" => flavor, | 
					
						
							|  |  |  |  | #        "Placement.AvailabilityZone" => s.options[:availability_zone], | 
					
						
							| 
									
										
										
										
											2016-01-27 15:44:59 +03:00
										 |  |  |  |         "KeyName" => self.ssh_key, | 
					
						
							|  |  |  |  |         "PrivateIpAddress" => s.private_ip | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       } | 
					
						
							|  |  |  |  |       vpcId = nil | 
					
						
							| 
									
										
										
										
											2015-08-05 14:05:14 +03:00
										 |  |  |  |       unless subnets.empty? | 
					
						
							|  |  |  |  |         options["SubnetId"] = subnets[0] | 
					
						
							| 
									
										
										
										
											2015-11-13 17:22:55 +03:00
										 |  |  |  |         network = self.networks.detect{|n| n["name"] == options["SubnetId"]} | 
					
						
							|  |  |  |  |         vpcId = network["vpcId"] if network | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |         if vpcId.nil? | 
					
						
							|  |  |  |  |           out << "Can not get 'vpcId' by subnet name '#{options["SubnetId"]}'\n" | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |           return false | 
					
						
							|  |  |  |  |         end | 
					
						
							|  |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-08-05 14:05:14 +03:00
										 |  |  |  |       options["SecurityGroupId"] = extract_group_ids(groups, vpcId).join(",") | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       aws_server = nil | 
					
						
							|  |  |  |  |       compute = self.compute | 
					
						
							|  |  |  |  |       begin | 
					
						
							| 
									
										
										
										
											2015-08-05 14:05:14 +03:00
										 |  |  |  |         aws_server = compute.run_instances(image, 1, 1, options) | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       rescue Excon::Errors::Unauthorized => ue | 
					
						
							|  |  |  |  |         #root = XML::Parser.string(ue.response.body).parse.root | 
					
						
							|  |  |  |  |         #msg = root.children.find { |node| node.name == "Message" } | 
					
						
							|  |  |  |  |         #code = root.children.find { |node| node.name == "Code" } | 
					
						
							|  |  |  |  |         code = "TODO" | 
					
						
							|  |  |  |  |         msg = ue.response.body | 
					
						
							|  |  |  |  |         out << "\nERROR: Unauthorized (#{code}: #{msg})" | 
					
						
							|  |  |  |  |         return false | 
					
						
							|  |  |  |  |       rescue Fog::Compute::AWS::Error => e | 
					
						
							|  |  |  |  |         out << e.message | 
					
						
							|  |  |  |  |         return false | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       abody = aws_server.body | 
					
						
							|  |  |  |  |       instance = abody["instancesSet"][0] | 
					
						
							|  |  |  |  |       s.id = instance["instanceId"] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       out << "\nWaiting for server..." | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       details, state = nil, instance["instanceState"]["name"] | 
					
						
							|  |  |  |  |       until state == "running" | 
					
						
							|  |  |  |  |         sleep(2) | 
					
						
							|  |  |  |  |         details = compute.describe_instances("instance-id" => [s.id]).body["reservationSet"][0]["instancesSet"][0] | 
					
						
							|  |  |  |  |         state = details["instanceState"]["name"].to_s | 
					
						
							|  |  |  |  |         next if state == "pending" or state == "running" | 
					
						
							|  |  |  |  |         out << "Server returns state '#{state}'" | 
					
						
							|  |  |  |  |         return false | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |       s.public_ip = details["ipAddress"] | 
					
						
							|  |  |  |  |       s.private_ip = details["privateIpAddress"] | 
					
						
							| 
									
										
										
										
											2015-11-23 14:55:53 +03:00
										 |  |  |  |       tags = server_tags(s) | 
					
						
							|  |  |  |  |       compute.create_tags(s.id, tags) | 
					
						
							| 
									
										
										
										
											2015-09-21 17:41:40 +03:00
										 |  |  |  |       out << "\nServer tags: #{tags.inspect}\n" | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       out << "\nDone\n\n" | 
					
						
							|  |  |  |  |       out << s.info | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       true | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-23 14:55:53 +03:00
										 |  |  |  |     def server_tags server | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         "Name" => server.chef_node_name, | 
					
						
							|  |  |  |  |         "cid:project" => server.project, | 
					
						
							|  |  |  |  |         "cid:deployEnv" => server.deploy_env, | 
					
						
							|  |  |  |  |         "cid:user" => server.created_by, | 
					
						
							|  |  |  |  |         "cid:remoteUser" => server.remote_user | 
					
						
							| 
									
										
										
										
											2015-09-16 14:07:46 +03:00
										 |  |  |  |       } | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def delete_server s | 
					
						
							|  |  |  |  |       r = self.compute.terminate_instances(s.id) | 
					
						
							|  |  |  |  |       i = r.body["instancesSet"][0] | 
					
						
							|  |  |  |  |       old_state = i["previousState"]["name"] | 
					
						
							|  |  |  |  |       state = i["currentState"]["name"] | 
					
						
							|  |  |  |  |       return r.status == 200 ? "Server with id '#{s.id}' changed state '#{old_state}' to '#{state}'" : r.body | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def pause_server s | 
					
						
							|  |  |  |  |       es = self.server s.id | 
					
						
							|  |  |  |  |       if es["state"] == "running" | 
					
						
							|  |  |  |  |         self.compute.stop_instances [ s.id ] | 
					
						
							|  |  |  |  |         return nil | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         return es["state"] | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def unpause_server s | 
					
						
							|  |  |  |  |       es = self.server s.id | 
					
						
							|  |  |  |  |       if es["state"] == "stopped" | 
					
						
							|  |  |  |  |         self.compute.start_instances [ s.id ] | 
					
						
							|  |  |  |  |         return nil | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         return es["state"] | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-03 18:01:50 +03:00
										 |  |  |  |     def set_tags instance_id, tags | 
					
						
							| 
									
										
										
										
											2015-08-04 09:56:03 +03:00
										 |  |  |  |       raise ConflictException.new("You can not change 'Name' tag") if tags.key?("Name") | 
					
						
							| 
									
										
										
										
											2015-08-03 18:01:50 +03:00
										 |  |  |  |       compute.create_tags(instance_id, tags) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def unset_tags instance_id, tags | 
					
						
							| 
									
										
										
										
											2015-08-04 09:56:03 +03:00
										 |  |  |  |       raise ConflictException.new("You can not change 'Name' tag") if tags.key?("Name") | 
					
						
							| 
									
										
										
										
											2015-08-03 18:01:50 +03:00
										 |  |  |  |       compute.delete_tags(instance_id, tags) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-20 12:59:17 +04:00
										 |  |  |  |     def compute | 
					
						
							|  |  |  |  |       connection_compute(connection_options) | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     def cloud_formation | 
					
						
							| 
									
										
										
										
											2015-11-19 14:09:38 +03:00
										 |  |  |  |       @cloud_formation ||= Fog::AWS::CloudFormation.new(connection_options) | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def create_stack(stack, out) | 
					
						
							|  |  |  |  |       begin | 
					
						
							|  |  |  |  |         out << "Creating stack for project '#{stack.project}' and environment '#{stack.deploy_env}'...\n" | 
					
						
							|  |  |  |  |         stack.name = create_default_stack_name(stack) unless stack.name | 
					
						
							|  |  |  |  |         out << "Stack name: #{stack.name}\n" | 
					
						
							|  |  |  |  |         out << "Stack template: #{stack.stack_template}\n" | 
					
						
							|  |  |  |  |         out << "Stack parameters: #{stack.parameters}\n" | 
					
						
							| 
									
										
										
										
											2015-08-18 17:53:39 +03:00
										 |  |  |  |         out.flush | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |         response = cloud_formation.create_stack(stack.name, | 
					
						
							|  |  |  |  |           { | 
					
						
							| 
									
										
										
										
											2016-01-27 15:44:59 +03:00
										 |  |  |  |             'TemplateURL' => stack.stack_template_model.template_url, | 
					
						
							| 
									
										
										
										
											2015-08-18 16:09:41 +03:00
										 |  |  |  |             'Parameters' => stack.parameters || {}, | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |  |             'Capabilities' => ['CAPABILITY_IAM'], | 
					
						
							| 
									
										
										
										
											2015-11-23 14:55:53 +03:00
										 |  |  |  |             'Tags' => stack_tags(stack) | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |           } | 
					
						
							|  |  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2015-08-18 17:41:17 +03:00
										 |  |  |  |         stack.id = response.body['StackId'] | 
					
						
							| 
									
										
										
										
											2015-08-18 16:27:35 +03:00
										 |  |  |  |         out << "Stack id: #{stack.id}\n" | 
					
						
							| 
									
										
										
										
											2015-08-18 17:53:39 +03:00
										 |  |  |  |         out.flush | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |       rescue Excon::Errors::Conflict => e | 
					
						
							|  |  |  |  |         raise ProviderErrors::NameConflict | 
					
						
							|  |  |  |  |       rescue Excon::Errors::BadRequest => br | 
					
						
							|  |  |  |  |         response = ::Chef::JSONCompat.from_json(br.response.body) | 
					
						
							|  |  |  |  |         if response['code'] == 400
 | 
					
						
							|  |  |  |  |           out << "\nERROR: Bad request (400): #{response['explanation']}" | 
					
						
							|  |  |  |  |           out << "\n" | 
					
						
							|  |  |  |  |           raise InvalidRecord.new(response['explanation']) | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |           out << "\nERROR: Unknown server error (#{response['code']}): #{response['explanation']}" | 
					
						
							|  |  |  |  |           out << "\n" | 
					
						
							|  |  |  |  |           raise InvalidRecord.new(response['explanation']) | 
					
						
							|  |  |  |  |         end | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-23 14:55:53 +03:00
										 |  |  |  |     def stack_tags stack | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         "StackTemplate" => stack.stack_template, | 
					
						
							|  |  |  |  |         "cid:project" => stack.project, | 
					
						
							|  |  |  |  |         "cid:deployEnv" => stack.deploy_env, | 
					
						
							|  |  |  |  |         "cid:user" => stack.owner | 
					
						
							| 
									
										
										
										
											2015-09-16 14:07:46 +03:00
										 |  |  |  |       } | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-23 16:34:14 +03:00
										 |  |  |  |     def update_stack(stack, params) | 
					
						
							|  |  |  |  |       cloud_formation.update_stack(stack.name, params) | 
					
						
							| 
									
										
										
										
											2015-09-16 14:07:46 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-21 19:03:53 +03:00
										 |  |  |  |     def validate_stack_template template | 
					
						
							| 
									
										
										
										
											2015-12-11 13:15:36 +03:00
										 |  |  |  |       #r = cloud_formation.validate_template({'TemplateBody' => template}) | 
					
						
							|  |  |  |  |       #pp r.body | 
					
						
							|  |  |  |  |       true | 
					
						
							| 
									
										
										
										
											2015-08-21 19:03:53 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |     def delete_stack(stack) | 
					
						
							| 
									
										
										
										
											2015-08-17 17:50:24 +03:00
										 |  |  |  |       cloud_formation.delete_stack(stack.name) | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def stack_details(stack) | 
					
						
							| 
									
										
										
										
											2015-09-21 17:34:20 +03:00
										 |  |  |  |       b = cloud_formation.describe_stacks({'StackName' => stack.name}).body | 
					
						
							| 
									
										
										
										
											2015-09-21 18:00:21 +03:00
										 |  |  |  |       b['Stacks'].detect{|s| s.key?("StackStatus")} || {} | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def stack_resources(stack) | 
					
						
							| 
									
										
										
										
											2015-08-17 17:50:24 +03:00
										 |  |  |  |       cloud_formation.describe_stack_resources({'StackName' => stack.name}).body['StackResources'] | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 13:23:13 +03:00
										 |  |  |  |     def stack_events(stack) | 
					
						
							| 
									
										
										
										
											2015-11-17 16:46:30 +03:00
										 |  |  |  |       cloud_formation.describe_stack_events(stack.name).body['StackEvents'].map{|se| {"timestamp" => se["Timestamp"], "stack_name" => se["StackName"], "stack_id" => se["StackId"], "event_id" => se["EventId"], "reason" => se["ResourceStatusReason"], "status" => se["ResourceStatus"]}}.sort{|se1, se2| se1["timestamp"] <=> se2["timestamp"]} | 
					
						
							| 
									
										
										
										
											2015-11-17 13:23:13 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-16 12:14:01 +03:00
										 |  |  |  |     # не работает, не используется | 
					
						
							|  |  |  |  |     # def stack_resource(stack, resource_id) | 
					
						
							|  |  |  |  |     #   physical_id = fog_stack(stack).resources.get(resource_id).physical_resource_id | 
					
						
							|  |  |  |  |     #   compute.servers.get(physical_id) | 
					
						
							|  |  |  |  |     # end | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     def stack_servers(stack) | 
					
						
							| 
									
										
										
										
											2015-09-16 12:14:01 +03:00
										 |  |  |  |       # orchestration.describe_stack_resources возвращает мало информации | 
					
						
							| 
									
										
										
										
											2015-09-16 12:33:37 +03:00
										 |  |  |  |       resources = compute.describe_instances( | 
					
						
							| 
									
										
										
										
											2015-09-16 12:14:01 +03:00
										 |  |  |  |         'tag-key' => 'aws:cloudformation:stack-id', | 
					
						
							|  |  |  |  |         'tag-value' => stack.id | 
					
						
							|  |  |  |  |       ).body["reservationSet"] | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-16 12:52:56 +03:00
										 |  |  |  |       # В ресурсах могут лежать не только конкретные инстансы, но и MasterNodesGroup, которые управляют | 
					
						
							|  |  |  |  |       # несколькими инстансами. Обрабатываем эту ситуацию. | 
					
						
							| 
									
										
										
										
											2015-09-16 12:33:37 +03:00
										 |  |  |  |       instances = resources.map { |resource| resource["instancesSet"] }.flatten | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       instances.map do |instance| | 
					
						
							| 
									
										
										
										
											2015-08-18 20:01:17 +03:00
										 |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2015-09-16 12:33:37 +03:00
										 |  |  |  |           # 'name' => instance["tagSet"]["Name"], | 
					
						
							| 
									
										
										
										
											2015-09-16 12:52:56 +03:00
										 |  |  |  |           'name' => [stack.name, instance_name(instance)].join('-'), | 
					
						
							| 
									
										
										
										
											2015-09-16 12:33:37 +03:00
										 |  |  |  |           'id' => instance["instanceId"], | 
					
						
							|  |  |  |  |           'key_name' => instance["keyName"], | 
					
						
							|  |  |  |  |           'private_ip' => instance["privateIpAddress"], | 
					
						
							|  |  |  |  |           'public_ip' => instance["ipAddress"], | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |  |           'tags' => instance["tagSet"] | 
					
						
							| 
									
										
										
										
											2015-08-18 20:01:17 +03:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-08-18 19:36:48 +03:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-18 16:02:55 +03:00
										 |  |  |  |     def create_default_stack_name s | 
					
						
							| 
									
										
										
										
											2015-08-28 17:00:48 +03:00
										 |  |  |  |       "stack-#{self.ssh_key}-#{s.project}-#{s.deploy_env}-#{Time.now.to_i}".gsub('_', '-') | 
					
						
							| 
									
										
										
										
											2015-08-18 16:02:55 +03:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-11-17 12:14:02 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     def describe_vpcs | 
					
						
							|  |  |  |  |       self.compute.describe_vpcs.body["vpcSet"].select{|v| v["state"] == "available"}.map{|v| {"vpc_id" => v["vpcId"], "cidr" => v["cidrBlock"] } } | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-01-27 15:44:59 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     def store_stack_template(filename, json) | 
					
						
							|  |  |  |  |       store_file(stack_templates_bucket, filename, json) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def store_file(bucket, filename, body) | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         'url' => bucket.files.create(key: filename, body: body, public: true).public_url | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |   private | 
					
						
							| 
									
										
										
										
											2015-09-16 12:14:01 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def convert_groups list | 
					
						
							|  |  |  |  |       res = {} | 
					
						
							|  |  |  |  |       list.each do |g| | 
					
						
							| 
									
										
										
										
											2014-11-20 15:08:42 +03:00
										 |  |  |  |         next if g["groupName"].nil? | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |         res[g["groupName"]] = { | 
					
						
							|  |  |  |  |           "description" => g["groupDescription"], | 
					
						
							|  |  |  |  |           "id" => g["groupId"] | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         rules = [] | 
					
						
							|  |  |  |  |         g["ipPermissions"].each do |r| | 
					
						
							|  |  |  |  |           cidr = r["ipRanges"][0] || {} | 
					
						
							|  |  |  |  |           rules.push({ | 
					
						
							|  |  |  |  |             "protocol" => r["ipProtocol"], | 
					
						
							|  |  |  |  |             "from" => r["fromPort"], | 
					
						
							|  |  |  |  |             "to" => r["toPort"], | 
					
						
							|  |  |  |  |             "cidr" => cidr["cidrIp"] | 
					
						
							|  |  |  |  |           }) | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |         end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |         res[g["groupName"]]["rules"] = rules | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       res | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def convert_server s | 
					
						
							|  |  |  |  |       { | 
					
						
							|  |  |  |  |         "state" => s["instanceState"]["name"], | 
					
						
							|  |  |  |  |         "name" => s["tagSet"]["Name"], | 
					
						
							|  |  |  |  |         "image" => s["imageId"], | 
					
						
							|  |  |  |  |         "flavor" => s["instanceType"], | 
					
						
							|  |  |  |  |         "keypair" => s["keyName"], | 
					
						
							|  |  |  |  |         "instance_id" => s["instanceId"], | 
					
						
							|  |  |  |  |         "dns_name" => s["dnsName"], | 
					
						
							|  |  |  |  |         "zone" => s["placement"]["availabilityZone"], | 
					
						
							|  |  |  |  |         "private_ip" => s["privateIpAddress"], | 
					
						
							|  |  |  |  |         "public_ip" => s["ipAddress"], | 
					
						
							|  |  |  |  |         "launched_at" => s["launchTime"] | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |     def extract_group_ids names, vpcId | 
					
						
							|  |  |  |  |       return [] if names.nil? | 
					
						
							|  |  |  |  |       p = nil | 
					
						
							|  |  |  |  |       p = {"vpc-id" => vpcId} unless vpcId.nil? | 
					
						
							|  |  |  |  |       groups = self.groups(p) | 
					
						
							|  |  |  |  |       r = names.map do |name| | 
					
						
							|  |  |  |  |         groups[name]["id"] | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-06-18 15:11:47 +04:00
										 |  |  |  |       r | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-08-17 11:25:20 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-16 12:14:01 +03:00
										 |  |  |  |     def orchestration | 
					
						
							|  |  |  |  |       @orchestration ||= Fog::AWS::CloudFormation.new(connection_options) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-27 15:44:59 +03:00
										 |  |  |  |     def storage | 
					
						
							|  |  |  |  |       @storage ||= Fog::Storage.new(connection_options) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def stack_templates_bucket | 
					
						
							|  |  |  |  |       bucket_name = DevopsConfig.config[:aws_stack_templates_bucket] || 'stacktemplatesnibrdev' | 
					
						
							|  |  |  |  |       bucket = storage.directories.get(bucket_name) | 
					
						
							|  |  |  |  |       bucket ||= storage.directories.create(key: bucket_name) | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-16 12:52:56 +03:00
										 |  |  |  |     def instance_name(instance) | 
					
						
							|  |  |  |  |       return instance["tagSet"]["Name"] if instance["tagSet"]["Name"] | 
					
						
							|  |  |  |  |       if instance['tagSet']['aws:autoscaling:groupName'] | 
					
						
							|  |  |  |  |         instance["instanceId"] | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         instance['tagSet']['aws:cloudformation:logical-id'] | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-08 15:34:26 +04:00
										 |  |  |  |   end | 
					
						
							|  |  |  |  | end |