def _Create(self): """Create a Rackspace instance.""" with tempfile.NamedTemporaryFile(dir=vm_util.GetTempDir(), prefix='user-data') as tf: with open(self.ssh_public_key) as f: public_key = f.read().rstrip('\n') script = CLOUD_CONFIG_TEMPLATE.format(self.user_name, public_key) tf.write(script) tf.flush() env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) create_cmd = self._GetCreateCommand() create_cmd.extend( ['--config-drive', 'true', '--user-data', tf.name, self.name]) stdout, _, _ = vm_util.IssueCommand(create_cmd, env=env) instance = util.ParseNovaTable(stdout) if 'id' in instance: self.id = instance['id'] else: raise errors.Resource.RetryableCreationError( 'There was a problem trying to create instance %s' % self.name) if not self._WaitForInstanceUntilActive(): raise errors.Resource.RetryableCreationError( 'Failed to create instance')
def Detach(self): """Detaches the disk from a VM.""" nova_env = os.environ.copy() nova_env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) detach_cmd = [ FLAGS.nova_path, 'volume-detach', self.attached_vm_name, self.id ] vm_util.IssueRetryableCommand(detach_cmd, env=nova_env) self.attached_vm_name = None
def AddMetadata(self, **kwargs): """Adds metadata to the Rackspace VM""" if not kwargs: return env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) cmd = [FLAGS.nova_path, 'meta', self.id, 'set'] for key, value in kwargs.iteritems(): cmd.append('{0}={1}'.format(key, value)) vm_util.IssueCommand(cmd, env=env)
def _Exists(self): """Returns true if the volume exists.""" nova_env = os.environ.copy() nova_env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) getdisk_cmd = [FLAGS.nova_path, 'volume-show', self.name] stdout, _, _ = vm_util.IssueCommand(getdisk_cmd, env=nova_env) if stdout.strip() == '': return False volume = util.ParseNovaTable(stdout) return 'status' in volume and volume['status'] == 'available'
def _Exists(self): """Returns true if the VM exists.""" env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) getinstance_cmd = [FLAGS.nova_path, 'show', self.id] stdout, stderr, _ = vm_util.IssueCommand(getinstance_cmd, env=env) if stdout.strip() == '': return False instance = util.ParseNovaTable(stdout) return (instance.get('OS-EXT-STS:task_state') == 'deleting' or instance.get('status') == 'ACTIVE')
def _GetFlavorDetails(self): """Retrieves details about the flavor used to build the instance. Returns: A dict of properties of the flavor used to build the instance. """ env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) flavor_show_cmd = [FLAGS.nova_path, 'flavor-show', self.machine_type] stdout, _, _ = vm_util.IssueCommand(flavor_show_cmd, env=env) flavor_properties = util.ParseNovaTable(stdout) return flavor_properties
def _PostCreate(self): """Get the instance's data.""" env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) getinstance_cmd = [FLAGS.nova_path, 'show', self.id] stdout, _, _ = vm_util.IssueCommand(getinstance_cmd, env=env) instance = util.ParseNovaTable(stdout) if 'status' in instance and instance['status'] == 'ACTIVE': self.ip_address = instance['accessIPv4'] self.ip_address6 = instance['accessIPv6'] self.internal_ip = instance['private network'] else: raise errors.Error('Unexpected failure.')
def _WaitForInstanceUntilActive(self, max_retries=720, poll_interval_secs=5): """Wait until instance achieves non-transient state.""" env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) getinstance_cmd = [FLAGS.nova_path, 'show', self.id] for _ in xrange(max_retries): time.sleep(poll_interval_secs) stdout, _, _ = vm_util.IssueCommand(getinstance_cmd, env=env) instance = util.ParseNovaTable(stdout) if 'status' in instance and instance['status'] != 'BUILD': return instance['status'] == 'ACTIVE' return False
def _Create(self): """Creates the volume.""" nova_env = os.environ.copy() nova_env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) create_cmd = [ FLAGS.nova_path, 'volume-create', '--display-name', self.name, '--volume-type', DISK_TYPE[self.disk_type], str(self.disk_size) ] stdout, _, _ = vm_util.IssueCommand(create_cmd, env=nova_env) volume = util.ParseNovaTable(stdout) if 'id' in volume and volume['id']: self.id = volume['id'] else: raise errors.Error('There was a problem when creating a volume.')
def CreateKeyPair(self): """Imports the public keyfile to Rackspace.""" with open(self.ssh_public_key) as f: public_key = f.read().rstrip('\n') with tempfile.NamedTemporaryFile(dir=vm_util.GetTempDir(), prefix='key-metadata') as tf: tf.write('%s\n' % public_key) tf.flush() env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) key_cmd = [ FLAGS.nova_path, 'keypair-add', '--pub-key', tf.name, self.key_name] vm_util.IssueRetryableCommand(key_cmd, env=env)
def _WaitForDiskUntilAttached(self, vm, max_retries=30, poll_interval_secs=5): """Wait until volume is attached to the instance.""" env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) volume_show_cmd = [FLAGS.nova_path, 'volume-show', self.id] for _ in xrange(max_retries): stdout, _, _ = vm_util.IssueCommand(volume_show_cmd, env=env) volume = util.ParseNovaTable(stdout) if 'attachments' in volume and vm.id in volume['attachments']: return True time.sleep(poll_interval_secs) return False
def Attach(self, vm): """Attaches the volume to a VM. Args: vm: The RackspaceVirtualMachine instance to which the volume will be attached. """ self.attached_vm_name = vm.name nova_env = os.environ.copy() nova_env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) attach_cmd = [ FLAGS.nova_path, 'volume-attach', self.attached_vm_name, self.id, "" ] vm_util.IssueRetryableCommand(attach_cmd, env=nova_env) if not self._WaitForDiskUntilAttached(vm): raise errors.Resource.RetryableCreationError( 'Failed to attach all scratch disks to vms. Exiting...')
def GetDevicePath(self): """Returns the path to the device inside the VM.""" nova_env = os.environ.copy() nova_env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) getdisk_cmd = [FLAGS.nova_path, 'volume-show', self.name] stdout, _, _ = vm_util.IssueCommand(getdisk_cmd, env=nova_env) volume = util.ParseNovaTable(stdout) attachment_list = [] if 'attachments' in volume and volume['attachments']: attachment_list = json.loads(volume['attachments']) if not attachment_list: raise errors.Error('Cannot determine volume %s attachments' % self.name) for attachment in attachment_list: if 'volume_id' in attachment and attachment['volume_id'] == self.id: return attachment['device'] else: raise errors.Error( 'Could not find device path in the volume %s attachments')
def _Delete(self): """Delete a Rackspace VM instance.""" env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) delete_cmd = [FLAGS.nova_path, 'delete', self.id] vm_util.IssueCommand(delete_cmd, env=env)
def DeleteKeyPair(self): """Deletes the imported keyfile for an account.""" env = os.environ.copy() env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) key_cmd = [FLAGS.nova_path, 'keypair-delete', self.key_name] vm_util.IssueCommand(key_cmd, env=env)
def _Delete(self): """Deletes the volume.""" nova_env = os.environ.copy() nova_env.update(util.GetDefaultRackspaceNovaEnv(self.zone)) delete_cmd = [FLAGS.nova_path, 'volume-delete', self.name] vm_util.IssueCommand(delete_cmd, env=nova_env)