2012-07-30 18:22:16 -04:00
require 'fog/compute/models/server'
2013-01-07 12:10:17 -05:00
require 'fog/rackspace/models/compute_v2/metadata'
2012-07-30 18:22:16 -04:00
module Fog
module Compute
class RackspaceV2
class Server < Fog :: Compute :: Server
# States
ACTIVE = 'ACTIVE'
BUILD = 'BUILD'
DELETED = 'DELETED'
ERROR = 'ERROR'
HARD_REBOOT = 'HARD_REBOOT'
MIGRATING = 'MIGRATING'
PASSWORD = 'PASSWORD'
REBOOT = 'REBOOT'
REBUILD = 'REBUILD'
RESCUE = 'RESCUE'
RESIZE = 'RESIZE'
REVERT_RESIZE = 'REVERT_RESIZE'
SUSPENDED = 'SUSPENDED'
UNKNOWN = 'UNKNOWN'
VERIFY_RESIZE = 'VERIFY_RESIZE'
2013-01-30 10:05:10 -05:00
# @!attribute [r] id
# @return [String] The server id
2012-07-30 18:22:16 -04:00
identity :id
2013-01-30 10:05:10 -05:00
# @!attribute [rw] name
# @return [String] The server name.
2012-07-30 18:22:16 -04:00
attribute :name
2013-01-30 10:05:10 -05:00
# @!attribute [r] created
# @return [String] The time stamp for the creation date.
2012-07-30 18:22:16 -04:00
attribute :created
2013-01-30 10:05:10 -05:00
# @!attribute [r] updated
# @return [String] The time stamp for the last update.
2012-07-30 18:22:16 -04:00
attribute :updated
2013-01-30 10:05:10 -05:00
# @!attribute [r] host Id
# The host Id.
# The compute provisioning algorithm has an anti-affinity property that attempts to spread customer VMs across hosts.
# Under certain situations, VMs from the same customer might be placed on the same host.
# hostId represents the host your server runs on and can be used to determine this scenario if it is relevant to your application.
# HostId is unique per account and is not globally unique.
# @return [String] host id.
2012-07-30 18:22:16 -04:00
attribute :host_id , :aliases = > 'hostId'
2013-01-30 10:05:10 -05:00
# @!attribute [r] state
# @return [String] server status.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/List_Servers-d1e2078.html#server_status
2012-07-30 18:22:16 -04:00
attribute :state , :aliases = > 'status'
2013-01-30 10:05:10 -05:00
# @!attribute [r] progress
# @return [Fixnum] The build completion progress, as a percentage. Value is from 0 to 100.
2012-07-30 18:22:16 -04:00
attribute :progress
2013-01-30 10:05:10 -05:00
# @!attribute [r] user_id
# @return [String] The user Id.
2012-07-30 18:22:16 -04:00
attribute :user_id
2013-01-30 10:05:10 -05:00
# @!attribute [r] tenant_id
# @return [String] The tenant Id.
2012-07-30 18:22:16 -04:00
attribute :tenant_id
2013-01-30 10:05:10 -05:00
# @!attribute [r] links
# @return [Array] Server links.
2012-07-30 18:22:16 -04:00
attribute :links
2013-01-30 10:05:10 -05:00
# @!attribute [rw] personality
# @note This attribute is only used for server creation. This field will be nil on subsequent retrievals.
# @return [Hash] Hash containing data to inject into the file system of the cloud server instance during server creation.
# @example To inject fog.txt into file system
# :personality => [{ :path => '/root/fog.txt',
# :contents => Base64.encode64('Fog was here!')
# }]
# @see #create
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Personality-d1e2543.html
2012-10-17 14:16:15 -04:00
attribute :personality
2013-01-30 10:05:10 -05:00
# @!attribute [rw] ipv4_address
# @return [String] The public IP version 4 access address.
# @note This field will populate once the server is ready to use.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Primary_Addresses-d1e2558.html
2012-07-30 18:22:16 -04:00
attribute :ipv4_address , :aliases = > 'accessIPv4'
2013-01-30 10:05:10 -05:00
# @!attribute [rw] ipv6_address
# @return [String] The public IP version 6 access address.
# @note This field will populate once the server is ready to use.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Server_Primary_Addresses-d1e2558.html
2012-07-30 18:22:16 -04:00
attribute :ipv6_address , :aliases = > 'accessIPv6'
2013-01-30 10:05:10 -05:00
# @!attribute [rw] disk_config
# @return [String<AUTO, MANUAL>] The disk configuration value.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ch_extensions.html#diskconfig_attribute
#
# The disk configuration value.
# * AUTO - The server is built with a single partition the size of the target flavor disk. The file system is automatically adjusted to fit the entire partition.
# This keeps things simple and automated. AUTO is valid only for images and servers with a single partition that use the EXT3 file system.
# This is the default setting for applicable Rackspace base images.
#
# * MANUAL - The server is built using whatever partition scheme and file system is in the source image. If the target flavor disk is larger,
# the remaining disk space is left unpartitioned. This enables images to have non-EXT3 file systems, multiple partitions,
# and so on, and enables you to manage the disk configuration.
2012-07-30 18:22:16 -04:00
attribute :disk_config , :aliases = > 'OS-DCF:diskConfig'
2013-01-30 10:05:10 -05:00
# @!attribute [r] bandwidth
# @return [Array] The amount of bandwidth used for the specified audit period.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ch_extensions.html#bandwidth_extension
2012-07-30 18:22:16 -04:00
attribute :bandwidth , :aliases = > 'rax-bandwidth:bandwidth'
2013-01-30 10:05:10 -05:00
# @!attribute [r] address
# @return [Hash<String, Array[Hash]>] IP addresses allocated for server by network
# @example
# {
# "public" => [
# {"version"=>4, "addr"=>"166.78.105.63"},
# {"version"=>6, "addr"=>"2001:4801:7817:0072:0fe1:75e8:ff10:61a9"}
# ],
# "private"=> [{"version"=>4, "addr"=>"10.177.18.209"}]
# }
2012-07-30 18:22:16 -04:00
attribute :addresses
2013-01-30 10:05:10 -05:00
# @!attribute [r] flavor_id
# @return [String] The flavor Id.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/List_Flavors-d1e4188.html
2012-07-30 18:22:16 -04:00
attribute :flavor_id , :aliases = > 'flavor' , :squash = > 'id'
2013-01-30 10:05:10 -05:00
# @!attribute [r] image_id
# @return [String] The image Id.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/List_Images-d1e4435.html
2012-07-30 18:22:16 -04:00
attribute :image_id , :aliases = > 'image' , :squash = > 'id'
2013-01-30 10:05:10 -05:00
# @!attribute [r] password
# @return [String] Password for system adminstrator account.
# @note This value is ONLY populated on server creation.
2013-01-10 16:48:30 -05:00
attr_reader :password
2013-01-31 22:55:49 -05:00
2013-01-07 12:10:17 -05:00
def initialize ( attributes = { } )
2013-01-08 10:09:43 -05:00
@service = attributes [ :service ]
2013-01-07 12:10:17 -05:00
super
2013-01-10 16:48:30 -05:00
end
2013-01-31 22:55:49 -05:00
2013-01-10 16:48:30 -05:00
alias :access_ipv4_address :ipv4_address
alias :access_ipv4_address = :ipv4_address =
alias :access_ipv6_address :ipv6_address
alias :access_ipv6_address = :ipv6_address =
2013-01-31 22:55:49 -05:00
2013-01-30 10:05:10 -05:00
# Server metadata
# @return [Fog::Compute::RackspaceV2::Metadata] metadata key value pairs.
2013-01-07 12:10:17 -05:00
def metadata
@metadata || = begin
Fog :: Compute :: RackspaceV2 :: Metadata . new ( {
2013-01-08 10:09:43 -05:00
:service = > service ,
2013-01-07 12:10:17 -05:00
:parent = > self
} )
end
end
2013-01-31 22:55:49 -05:00
2013-01-30 10:05:10 -05:00
# Set server metadata
# @param [Hash] hash contains key value pairs
2013-01-07 12:10:17 -05:00
def metadata = ( hash = { } )
metadata . from_hash ( hash )
end
2012-08-08 21:57:37 -04:00
2013-01-30 10:05:10 -05:00
# Saves the server.
# Creates server if it is new, otherwise it will update server attributes name, accessIPv4, and accessIPv6.
# @return [Boolean] true if server has started saving
2013-01-31 22:55:49 -05:00
def save ( options = { } )
2012-12-22 21:45:05 -05:00
if persisted?
2012-07-30 18:22:16 -04:00
update
else
2013-01-31 22:55:49 -05:00
create ( options )
2012-07-30 18:22:16 -04:00
end
true
end
2013-01-30 10:05:10 -05:00
# Creates server
# * requires attributes: service:, :name, :image_id, and :flavor_id
# * optional attributes :disk_config, :metadata, :personality
# @return [Boolean] returns true if server is being created
# @note You should use servers.create to create servers instead calling this method directly
# @see Servers#create
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/CreateServers.html
#
# * State Transitions
# * BUILD -> ACTIVE
# * BUILD -> ERROR (on error)
2013-01-31 22:55:49 -05:00
def create ( options )
2012-07-30 18:22:16 -04:00
requires :name , :image_id , :flavor_id
2012-10-17 14:16:15 -04:00
2012-10-09 12:24:08 -04:00
options [ :disk_config ] = disk_config unless disk_config . nil?
2013-01-22 16:34:52 -05:00
options [ :metadata ] = metadata . to_hash unless @metadata . nil?
2012-10-17 14:16:15 -04:00
options [ :personality ] = personality unless personality . nil?
2012-11-09 20:37:22 -05:00
2013-01-31 22:55:49 -05:00
if options [ :networks ]
options [ :networks ] . map! { | id | { :uuid = > id } }
end
2012-12-22 18:24:03 -05:00
data = service . create_server ( name , image_id , flavor_id , 1 , 1 , options )
2012-07-30 18:22:16 -04:00
merge_attributes ( data . body [ 'server' ] )
true
end
2013-01-30 10:05:10 -05:00
# Updates server
# This will update :name, :accessIPv4, and :accessIPv6 attributes.
# @note If you edit the server name, the server host name does not change. Also, server names are not guaranteed to be unique.
# @return true if update has started updating
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/ServerUpdate.html
#
# * State Transition
# * ACTIVE -> ACTIVE
2012-07-30 18:22:16 -04:00
def update
2013-01-10 16:48:30 -05:00
requires :identity
options = {
'name' = > name ,
'accessIPv4' = > ipv4_address ,
'accessIPv6' = > ipv6_address
}
2013-01-31 22:55:49 -05:00
2013-01-10 16:48:30 -05:00
data = service . update_server ( identity , options )
2012-07-30 18:22:16 -04:00
merge_attributes ( data . body [ 'server' ] )
true
end
2013-01-30 10:05:10 -05:00
# Destroy the server
# @return [Boolean] returns true if server has started deleting
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Delete_Server-d1e2883.html
#
# * Status Transition:
# * ACTIVE -> DELETED
# * ERROR -> DELETED
2012-07-30 18:22:16 -04:00
def destroy
requires :identity
2012-12-22 18:24:03 -05:00
service . delete_server ( identity )
2012-07-30 18:22:16 -04:00
true
end
2013-01-30 10:05:10 -05:00
# Server flavor
# @return [Fog::Compute::RackspaceV2::Flavor] server flavor
2012-07-30 18:22:16 -04:00
def flavor
requires :flavor_id
2012-12-22 18:24:03 -05:00
@flavor || = service . flavors . get ( flavor_id )
2012-07-30 18:22:16 -04:00
end
2013-01-30 10:05:10 -05:00
# Server image
# @return [Fog::Compute::RackspaceV2::Image] server image
2012-07-30 18:22:16 -04:00
def image
requires :image_id
2012-12-22 18:24:03 -05:00
@image || = service . images . get ( image_id )
2012-07-30 18:22:16 -04:00
end
2012-12-22 18:24:03 -05:00
2013-01-30 10:05:10 -05:00
# Creates Image from server. Once complete, a new image is available that you can use to rebuild or create servers.
# @param name [String] name of image to create
# @param options [Hash]:
# @option options [Hash<String, String>] metadata hash of containing metadata key value pairs.
# @return [Fog::ComputeRackspaceV2::Image] image being created
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Create_Image-d1e4655.html
#
# * State Transition:
# * SAVING -> ACTIVE
# * SAVING -> ERROR (on error)
2012-12-11 09:35:06 -05:00
def create_image ( name , options = { } )
requires :identity
2012-12-22 18:24:03 -05:00
response = service . create_image ( identity , name , options )
2013-01-31 22:55:49 -05:00
begin
2013-01-14 17:50:50 -05:00
image_id = response . headers [ " Location " ] . match ( / \/ ([^ \/ ]+$) / ) [ 1 ]
Fog :: Compute :: RackspaceV2 :: Image . new ( :collection = > service . images , :service = > service , :id = > image_id )
rescue
nil
end
2012-12-11 09:35:06 -05:00
end
2012-07-30 18:22:16 -04:00
2013-01-30 10:05:10 -05:00
# Attached Cloud Block Volumes
# @return [Fog::Compute::RackspaceV2::Attachments] attached Cloud Block Volumes
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/List_Volume_Attachments.html
2012-08-30 11:02:14 -04:00
def attachments
@attachments || = begin
Fog :: Compute :: RackspaceV2 :: Attachments . new ( {
2012-12-22 18:24:03 -05:00
:service = > service ,
2012-08-30 11:02:14 -04:00
:server = > self
} )
end
end
2013-01-31 22:55:49 -05:00
2013-01-30 10:05:10 -05:00
# Attaches Cloud Block Volume
# @param [Fog::Rackspace::BlockStorage::Volume, String] volume object or the volume id of volume to mount
# @param [String] device name of the device /dev/xvd[a-p] (optional)
# @return [Fog::Compute::RackspaceV2::Attachment] resulting attachment object
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Attach_Volume_to_Server.html
2013-01-11 09:29:53 -05:00
def attach_volume ( volume , device = nil )
2013-01-09 15:54:02 -05:00
requires :identity
volume_id = volume . is_a? ( String ) ? volume : volume . id
attachments . create ( :server_id = > identity , :volume_id = > volume_id , :device = > device )
2013-01-31 22:55:49 -05:00
end
2012-12-22 18:24:03 -05:00
2013-01-30 10:05:10 -05:00
# Server's private IPv4 address
# @return [String] private IPv4 address
2012-11-01 15:33:54 -04:00
def private_ip_address
addresses [ 'private' ] . select { | a | a [ " version " ] == 4 } [ 0 ] [ " addr " ]
end
2013-01-30 10:05:10 -05:00
# Server's public IPv4 address
# @return [String] public IPv4 address
2012-11-01 15:33:54 -04:00
def public_ip_address
ipv4_address
end
2012-08-30 11:02:14 -04:00
2013-01-30 10:05:10 -05:00
# Is server is in ready state
# @param [String] ready_state By default state is ACTIVE
# @param [Array,String] error_states By default state is ERROR
# @return [Boolean] returns true if server is in a ready state
# @raise [RuntimeException] if server state is an error state
2013-01-11 17:36:07 -05:00
def ready? ( ready_state = ACTIVE , error_states = [ ERROR ] )
if error_states
error_states = Array ( error_states )
2013-01-14 09:36:21 -05:00
raise " Server should have transitioned to ' #{ ready_state } ' not ' #{ state } ' " if error_states . include? ( state )
2013-01-11 17:36:07 -05:00
end
state == ready_state
2012-07-30 18:22:16 -04:00
end
2013-01-30 10:05:10 -05:00
# Reboot server
# @param [String<SOFT, HARD>] type 'SOFT' will do a soft reboot. 'HARD' will do a hard reboot.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Reboot_Server-d1e3371.html
#
# * State transition:
# * ACTIVE -> REBOOT -> ACTIVE (soft reboot)
# * ACTIVE -> HARD_REBOOT -> ACTIVE (hard reboot)
2012-07-30 18:22:16 -04:00
def reboot ( type = 'SOFT' )
requires :identity
2012-12-22 18:24:03 -05:00
service . reboot_server ( identity , type )
2012-07-30 18:22:16 -04:00
self . state = type == 'SOFT' ? REBOOT : HARD_REBOOT
true
end
2013-01-30 10:05:10 -05:00
# Rebuild removes all data on the server and replaces it with the specified image. The id and all IP addresses remain the same.
# @param [String] image_id image to use for rebuild
# @return [Boolean] returns true if rebuild is in process
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Rebuild_Server-d1e3538.html
#
# * Status Transition:
# * ACTIVE -> REBUILD -> ACTIVE
# * ACTIVE -> REBUILD -> ERROR (on error)
2013-01-08 11:53:43 -05:00
def rebuild ( image_id , options = { } )
2012-07-30 18:22:16 -04:00
requires :identity
2013-01-08 11:53:43 -05:00
service . rebuild_server ( identity , image_id , options )
2012-07-30 18:22:16 -04:00
self . state = REBUILD
true
end
2013-01-30 10:05:10 -05:00
# Resize existing server to a different flavor, in essence, scaling the server up or down. The original server is saved for a period of time to allow rollback if there is a problem. All resizes should be tested and explicitly confirmed, at which time the original server is removed. All resizes are automatically confirmed after 24 hours if they are not confirmed or reverted.
# @param [String] flavor to resize
# @return [Boolean] returns true if resize is in process
# @note All resizes are automatically confirmed after 24 hours if you do not explicitly confirm or revert the resize.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Resize_Server-d1e3707.html
# @see #confirm_resize
# @see #revert_resize
#
# * Status Transition:
# * ACTIVE -> QUEUE_RESIZE -> PREP_RESIZE -> VERIFY_RESIZE
# * ACTIVE -> QUEUE_RESIZE -> ACTIVE (on error)
def resize ( flavor_id )
requires :identity
service . resize_server ( identity , flavor_id )
self . state = RESIZE
true
end
# Confirms server resize operation
# @note All resizes are automatically confirmed after 24 hours if you do not explicitly confirm or revert the resize.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Confirm_Resized_Server-d1e3868.html
# @see #resize
#
# * Status Transition:
# * VERIFY_RESIZE -> ACTIVE
# * VERIFY_RESIZE -> ERROR (on error)
2012-07-30 18:22:16 -04:00
def confirm_resize
requires :identity
2012-12-22 18:24:03 -05:00
service . confirm_resize_server ( identity )
2012-07-30 18:22:16 -04:00
true
end
2013-01-30 10:05:10 -05:00
# Reverts server resize operation
# @note All resizes are automatically confirmed after 24 hours if you do not explicitly confirm or revert the resize.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Revert_Resized_Server-d1e4024.html
# @see #resize
#
# * Status Transition:
# * VERIFY_RESIZE -> ACTIVE
# * VERIFY_RESIZE -> ERROR (on error)
2012-07-30 18:22:16 -04:00
def revert_resize
requires :identity
2012-12-22 18:24:03 -05:00
service . revert_resize_server ( identity )
2012-07-30 18:22:16 -04:00
true
end
2013-01-30 10:05:10 -05:00
# Change admin password
# @param [String] password The administrator password.
# @return [Boolean] returns true if operation was scheduled
# @note Though Rackspace does not enforce complexity requirements for the password, the operating system might. If the password is not complex enough, the server might enter an ERROR state.
# @see http://docs.rackspace.com/servers/api/v2/cs-devguide/content/Change_Password-d1e3234.html
#
# * Status Transition:
# * ACTIVE -> PASSWORD -> ACTIVE
# * ACTIVE -> PASSWORD -> ERROR (on error)
2012-07-30 18:22:16 -04:00
def change_admin_password ( password )
requires :identity
2012-12-22 18:24:03 -05:00
service . change_server_password ( identity , password )
2012-07-30 18:22:16 -04:00
self . state = PASSWORD
2012-08-08 21:57:37 -04:00
@password = password
2012-07-30 18:22:16 -04:00
true
end
2012-12-22 18:24:03 -05:00
2013-01-30 10:05:10 -05:00
# Setup server for SSH access
# This requires public_key_path and private_key_path to be passed into Compute service via Fog::Compute constructor or .fog file
# @see Servers#bootstrap
2012-11-01 16:24:43 -04:00
def setup ( credentials = { } )
requires :public_ip_address , :identity , :public_key , :username
Fog :: SSH . new ( public_ip_address , username , credentials ) . run ( [
%{ mkdir .ssh } ,
%{ echo " #{ public_key } " >> ~/.ssh/authorized_keys } ,
%{ passwd -l #{ username } } ,
%{ echo " #{ Fog :: JSON . encode ( attributes ) } " >> ~/attributes.json } ,
%{ echo " #{ Fog :: JSON . encode ( metadata ) } " >> ~/metadata.json }
] )
rescue Errno :: ECONNREFUSED
sleep ( 1 )
retry
end
2012-08-08 21:57:37 -04:00
private
def adminPass = ( new_admin_pass )
@password = new_admin_pass
end
2012-07-30 18:22:16 -04:00
end
end
end
end