class Inception::InceptionServer
Constants
- DEFAULT_DISK_SIZE
- DEFAULT_FLAVOR
- DEFAULT_SECURITY_GROUPS
- DEFAULT_SERVER_NAME
Attributes
Public Class Methods
@provider_client [Inception::Providers::FogProvider] - interact with IaaS @attributes [ReadWriteSettings]
Required @attributes:
{ "name" => "inception", "ip_address" => "54.214.15.178", "key_pair" => { "name" => "inception", "private_key" => "private_key", "public_key" => "public_key" } }
Including optional @attributes and default values:
{ "name" => "inception", "ip_address" => "54.214.15.178", "security_groups" => ["ssh"], "flavor" => "m1.small", "key_pair" => { "name" => "inception", "private_key" => "private_key", "public_key" => "public_key" } }
# File lib/inception/inception_server.rb, line 39 def initialize(provider_client, attributes, ssh_dir) @provider_client = provider_client @ssh_dir = ssh_dir @attributes = attributes.is_a?(Hash) ? ReadWriteSettings.new(attributes) : attributes raise "@attributes must be ReadWriteSettings (or Hash)" unless @attributes.is_a?(ReadWriteSettings) end
Public Instance Methods
Create the underlying server, with key pair & security groups, unless it is already created
The @attributes hash is updated with a `provisioned` key during/after creation. When saved as YAML it might look like:
inception: provisioned: image_id: ami-123456 server_id: i-e7f005d2 security_groups: - ssh - mosh username: ubuntu disk_device: /dev/sdi host: ec2-54-214-15-178.us-west-2.compute.amazonaws.com validated: true converged: true
# File lib/inception/inception_server.rb, line 62 def create validate_attributes_for_bootstrap ensure_required_security_groups create_missing_default_security_groups bootstrap_vm attach_persistent_disk end
# File lib/inception/inception_server.rb, line 192 def default_disk_device case @provider_client when Inception::Providers::Clients::AwsProviderClient { "external" => "/dev/sdf", "internal" => "/dev/xvdf" } when Inception::Providers::Clients::OpenStackProviderClient { "external" => "/dev/vdc", "internal" => "/dev/vdc" } else raise "Please implement InceptionServer#default_disk_device for #{@provider_client.class}" end end
Delete the server, volume and release the IP address
# File lib/inception/inception_server.rb, line 71 def delete_all delete_server delete_volume delete_key_pair release_ip_address end
# File lib/inception/inception_server.rb, line 106 def delete_key_pair key_pair_name = attributes.exists?("key_pair.name") if key_pair_name && key_pair = fog_compute.key_pairs.get(key_pair_name) puts "Deleting key pair '#{key_pair_name}'" key_pair.destroy else puts "Keypair already destroyed" end attributes.delete("key_pair") end
# File lib/inception/inception_server.rb, line 78 def delete_server @fog_server = nil # force reload of fog_server model if fog_server print "Deleting server... " fog_server.destroy wait_for_termination(fog_server) unless Fog.mocking? puts "done." else puts "Server already destroyed" end provisioned.delete("host") provisioned.delete("server_id") provisioned.delete("username") end
# File lib/inception/inception_server.rb, line 93 def delete_volume volume_id = provisioned.exists?("disk_device.volume_id") if volume_id && (volume = fog_compute.volumes.get(volume_id)) && volume.ready? print "Deleting volume... " volume.destroy wait_for_termination(volume, "deleting") puts "" else puts "Volume already destroyed" end provisioned.delete("disk_device") end
# File lib/inception/inception_server.rb, line 184 def disk_devices provisioned["disk_device"] ||= default_disk_device end
Size of attached persistent disk for the inception server
# File lib/inception/inception_server.rb, line 157 def disk_size @attributes["disk_size"] ||= DEFAULT_DISK_SIZE end
Because @attributes is not the same as @attributes.provisioned we need a helper to export the complete nested attributes.
# File lib/inception/inception_server.rb, line 178 def export_attributes attrs = attributes.to_nested_hash attrs["provisioned"] = provisioned.to_nested_hash attrs end
# File lib/inception/inception_server.rb, line 188 def external_disk_device disk_devices["external"] end
Flavor/instance type of the server to be provisioned TODO: DEFAULT_FLAVOR
should become IaaS/provider specific
# File lib/inception/inception_server.rb, line 152 def flavor @attributes["flavor"] ||= DEFAULT_FLAVOR end
# File lib/inception/inception_server.rb, line 215 def fog_compute @provider_client.fog_compute end
# File lib/inception/inception_server.rb, line 207 def fog_server @fog_server ||= begin if server_id = provisioned["server_id"] fog_compute.servers.get(server_id) end end end
# File lib/inception/inception_server.rb, line 165 def image_id @attributes["image_id"] ||= @provider_client.image_id end
# File lib/inception/inception_server.rb, line 161 def ip_address provisioned.ip_address end
# File lib/inception/inception_server.rb, line 138 def key_name @attributes.key_pair.name end
# File lib/inception/inception_server.rb, line 142 def private_key_path @private_key_path ||= File.join(@ssh_dir, key_name) end
The progresive/final attributes of the provisioned Inception
server & persistent disk.
# File lib/inception/inception_server.rb, line 171 def provisioned @attributes["provisioned"] = {} unless @attributes["provisioned"] @attributes.provisioned end
# File lib/inception/inception_server.rb, line 146 def public_key @attributes.exists?("key_pair.public_key") end
# File lib/inception/inception_server.rb, line 118 def release_ip_address public_ip = provisioned.exists?("ip_address") if public_ip && ip_address = fog_compute.addresses.get(public_ip) puts "Releasing IP address #{public_ip}" ip_address.destroy else puts "IP address already released" end provisioned.delete("ip_address") end
# File lib/inception/inception_server.rb, line 129 def security_groups @attributes.security_groups end
# File lib/inception/inception_server.rb, line 133 def server_name @attributes["name"] ||= DEFAULT_SERVER_NAME @attributes.name end
# File lib/inception/inception_server.rb, line 203 def user_host "#{provisioned.username}@#{provisioned.host}" end
Protected Instance Methods
# File lib/inception/inception_server.rb, line 268 def attach_persistent_disk unless Fog.mocking? print "Confirming ssh access to server... " Fog.wait_for(60) { fog_server.sshable?(ssh_options) } puts "done" end unless volume = @provider_client.find_server_device(fog_server, external_disk_device) print "Provisioning #{disk_size}Gb persistent disk for inception server... " volume = @provider_client.create_and_attach_volume("Inception Disk", disk_size, fog_server, external_disk_device) disk_devices["volume_id"] = volume.id puts disk_devices.volume_id end set_resource_name(volume, server_name) end
# File lib/inception/inception_server.rb, line 256 def bootstrap_vm unless fog_server print "Booting #{flavor} inception server... " @fog_server = @provider_client.bootstrap(fog_attributes) provisioned["server_id"] = fog_server.id provisioned["host"] = fog_server.dns_name || fog_server.public_ip_address provisioned["username"] = fog_attributes[:username] puts provisioned.server_id end set_resource_name(fog_server, server_name) end
# File lib/inception/inception_server.rb, line 251 def create_missing_default_security_groups # provider method only creates group if missing @provider_client.create_security_group("ssh", "ssh", {ssh: 22}) end
ssh group must be first (bootstrap method looks for port 22 in first group)
# File lib/inception/inception_server.rb, line 241 def ensure_required_security_groups if @attributes["security_groups"] && @attributes["security_groups"].is_a?(Array) unless @attributes["security_groups"].include?("ssh") @attributes["security_groups"] = ["ssh", *@attributes["security_groups"]] end else @attributes["security_groups"] = ["ssh"] end end
# File lib/inception/inception_server.rb, line 227 def fog_attributes @provider_client.fog_attributes(self) end
TODO emit events rather than writing directly to STDOUT
# File lib/inception/inception_server.rb, line 300 def say(*args) puts(*args) end
set_resource_name
(fog_server
, “inception”) set_resource_name
(volume, “inception-root”) set_resource_name
(volume, “inception-store”)
# File lib/inception/inception_server.rb, line 223 def set_resource_name(resource, name) @provider_client.set_resource_name(resource, name) end
# File lib/inception/inception_server.rb, line 284 def ssh_options { keys: [private_key_path] } end
# File lib/inception/inception_server.rb, line 231 def validate_attributes_for_bootstrap missing_attributes = [] missing_attributes << "provisioned.ip_address" unless @attributes.exists?("provisioned.ip_address") missing_attributes << "key_pair.private_key" unless @attributes.exists?("key_pair.private_key") if missing_attributes.size > 0 raise "Missing InceptionServer attributes: #{missing_attributes.join(', ')}" end end
Poll a fog model until it terminates; print . each second
# File lib/inception/inception_server.rb, line 291 def wait_for_termination(fog_model, state_to_wait_for="terminated") fog_model.wait_for do print "." state == state_to_wait_for end end