public function cmd_refresh() { $args = func_get_args(); $this->Out->debug(__METHOD__,$args); // Define the meta for this command if(isset($args[0]) && $args[0] == '__meta') { return array( 'command' => str_replace('cmd_','',__FUNCTION__), 'description' => 'Manually cause a refresh of all cloud resource data', 'sub_commands' => array() ); } // Update instances data $this->Cloud->refreshCloudData(); $this->Out->msg(); }
/** * instanceStart * * @param string $name * @param int $count */ public function instanceStart($name,$count='1',$return_launch_spec_only=false) { $this->Out->debug(__METHOD__,func_get_args()); // Update all data $this->Cloud->refreshCloudData(); // Determine the ami platform $platform = $this->getAttribute($name,'platform','config'); if(empty($platform)) { try { $response = $this->Cloud->EC2->describe_images(array( 'ImageId' => $this->getAttribute($name,'imageId','config') )); } catch (RequestCore_Exception $e) {} $platform = (string) $response->{'body'}->{'imagesSet'}->{'item'}->{'platform'}; } if(empty($platform)) { $this->Out->error("Unable to determine instance image platform. Resolve this by adding a 'platform' configuration item to this instance definition."); return false; } // The array of user data files $user_data_scripts = array(); // Add the update_sources script first if required for this instance $update_platform = $this->getAttribute($name,'tagUpdatePlatform','config'); if('true' == strtolower($update_platform) || '1' == $update_platform || 'yes' == strtolower($update_platform)) { $user_data_scripts[] = $this->getScript('bootstrap/'.strtolower($platform).'/update-platform'); } // Add dependancies as required $user_data_scripts[] = $this->getScript('bootstrap/'.strtolower($platform).'/install-dependencies'); // Make sure this instance exists if(!in_array($name,$this->getNames('config'))) { $this->Out->error('Unknown instance: '.$name); return false; } // If address assigned check that it is available $address_id = $this->getAttribute($name,'address','config'); if(!empty($address_id) && $this->Cloud->Address->getAttribute($address_id,'instanceId')) { $this->Out->error('Required address '.$address_id.' is already in use by another instance'); return false; } // If volumes are assigned check they are all available $volumes = $this->getAttribute($name,'volumes','config'); if(!empty($volumes)) { foreach($volumes as $volume_id) { if($this->Cloud->Volume->getAttribute($volume_id,'instanceId')) { $this->Out->error('Required volume '.$volume_id.' is already in use by another instance'); return false; } // Establish scripts for volume mounts $user_data_scripts[] = $this->getScript('bootstrap/common/mount-volume',$this->Cloud->Volume->getAttribute($volume_id,'device','config'),$this->Cloud->Volume->getAttribute($volume_id,'tagMount','config')); } } // If there is a count value > 1 make sure we are not attempting to assocaite any volumes or addresses if($count > 1) { if(!empty($address_id)) { $this->Out->error('Cannot start multiple instances using the same address: '.$address_id); return false; } if(!empty($volumes)) { $this->Out->error('Cannot start multiple instances using the same volumes: '.join(',',$volumes)); return false; } } // Establish the associated recipe scripts $recipes = $this->getAttribute($name,'tagRecipes','config'); if(!empty($recipes)) { foreach($recipes as $recipe) { $script = $this->getScript('recipes/'.strtolower($platform).'/'.$recipe); if(empty($script)) { $script = $this->getScript(strtolower($platform).'/'.$recipe); if(empty($script)) { $script = $this->getScript($recipe); if(empty($script)) { $this->Out->error('Unable to locate recipe for: '.$recipe); return false; } } } $user_data_scripts[] = $script; } } // Add our own package install scripts $packages = $this->getAttribute($name,'tagPackages','config'); if(!empty($packages)) { foreach($packages as $package_name) { // Confirm the package name $timestamp_revision = null; if(preg_match("/^(.*?)-(\d\d\d\d\d\d\d\d-\d\d\d\d\d\d)/",$package_name,$matches)) { $package_name = $matches[1]; $timestamp_revision = $matches[2]; } $user_data_scripts[] = $this->Cloud->Package->getInstallScript($package_name,$timestamp_revision); } } // instance_id $instance_ids = array(); // Make sure ec2-run-instances is installed here $ec2_run_instances = $this->Cloud->SystemCommand->exec('which ec2-run-instances'); if($ec2_run_instances && isset($this->Cloud->config['aws']['private_key_file']) && isset($this->Cloud->config['aws']['certificate_file']) && !empty($this->Cloud->config['aws']['private_key_file']) && !empty($this->Cloud->config['aws']['certificate_file']) ) { // Make sure private_key_file and certificate_key_file are present $certificate_file = $this->Cloud->config['aws']['certificate_file']; $certificate_file = str_replace('~',getenv('HOME'),$certificate_file); if(!is_file($certificate_file)) { $this->Out->error('Unable to locate certificate_file: '.$certificate_file); return false; } $this->Out->msg('Using certificate_file: '.$certificate_file); $private_key_file = $this->Cloud->config['aws']['private_key_file']; $private_key_file = str_replace('~',getenv('HOME'),$private_key_file); if(!is_file($private_key_file)) { $this->Out->error('Unable to locate private_key_file: '.$private_key_file); return false; } $this->Out->msg('Using private_key_file: '.$private_key_file); // API target URL $this->Out->msg('API target: '.$this->Cloud->EC2->hostname); $cmd = 'ec2-run-instances '.$this->getAttribute($name,'imageId','config'); $cmd .= ' --cert '.$certificate_file; $cmd .= ' --private-key '.$private_key_file; $cmd .= ' --url '.$this->Cloud->EC2->hostname; $cmd .= ' --user-data-file '.$this->doPackageUserDataScripts($user_data_scripts,true); $cmd .= ' --region '.$this->Cloud->config['ec2']['region']; $cmd .= ' --instance-type '.$this->getAttribute($name,'instanceType','config'); $cmd .= ' --instance-count '.$count; //$cmd .= ' --ramdisk '; // do we really care about this? NdJ if($this->getAttribute($name,'keyName','config')) { $cmd .= ' --key '.$this->getAttribute($name,'keyName','config'); } if($this->getAttribute($name,'availabilityZone','config')) { $cmd .= ' --availability-zone '.$this->getAttribute($name,'availabilityZone','config'); } if($this->getAttribute($name,'kernelId','config')) { $cmd .= ' --kernel '.$this->getAttribute($name,'kernelId','config'); } foreach($this->getAttribute($name,'groups','config') as $group) { $cmd .= ' --group '.$group; } //$this->Out->error($cmd); $this->Out->msg('Starting instance(s) using ec2-run-instances',false); $response = $this->Cloud->SystemCommand->exec($cmd); //$this->Out->error($cmd); preg_match_all("/INSTANCE\s+(i-.+?)\s+ami/",$response,$matches); if(!isset($matches[1][0])) { $this->Out->error('Unable to start instance(s) using ec2-run-instances'); return false; } $this->Out->msg(' - done'); $instance_ids = $matches[1]; } else { $this->Out->msg('Starting '.$name.' using AWS SDK for PHP'); $config = array(); # KeyName if($this->getAttribute($name,'keyName','config')) { $config['KeyName'] = $this->getAttribute($name,'keyName','config'); } # SecurityGroup if($this->getAttribute($name,'groups','config')) { $config['SecurityGroup'] = $this->getAttribute($name,'groups','config'); } # UserData $config['UserData'] = base64_encode(file_get_contents($this->doPackageUserDataScripts($user_data_scripts,true,true))); # InstanceType if($this->getAttribute($name,'instanceType','config')) { $config['InstanceType'] = $this->getAttribute($name,'instanceType','config'); } # AvailabilityZone if($this->getAttribute($name,'availabilityZone','config')) { $config['Placement'] = array('AvailabilityZone'=>$this->getAttribute($name,'availabilityZone','config')); } # KernelId if($this->getAttribute($name,'kernelId','config')) { $config['KernelId'] = $this->getAttribute($name,'kernelId','config'); } // exit here to return this LaunchSpecification only if($return_launch_spec_only) { $config['ImageId'] = $this->getAttribute($name,'imageId','config'); return array($config); } //print_r($config);exit; try { $response = $this->Cloud->EC2->run_instances( $this->getAttribute($name,'imageId','config'), $count,$count,$config ); } catch (RequestCore_Exception $e) {} if(!$response->isOK()) { $this->Out->error('Unable to start instances - check if '.$this->getAttribute($name,'imageId','config').' is available in '.$this->Cloud->config['ec2']['region']); if(isset($e)) { $this->Out->error($e); } $this->Out->error(print_r($response,1)); return false; } foreach($response->{'body'}->{'instancesSet'}->{'item'} as $item) { $instance_ids[] = (string) $item->{'instanceId'}; } } // Make sure we received at least one instance_id if(empty($instance_ids)) { $this->Out->error('No instance started!'); return false; } $blocked = true; while($blocked) { // Ensure we have up-to-date instance data $this->getData(null,true); $data = null; foreach($instance_ids as $instance_id) { $state = $this->getAttribute($instance_id,'state','cloud'); if('running'==$state) { $this->Out->msg('Instance running: '.$instance_id); // Set all the tags for this instance $this->syncTags($name,$instance_id,array('tagName','tagRecipes','tagPackages','tagUpdatePlatform','tagUsername')); // Associate address if(!empty($address_id)) { if(!$this->Cloud->Address->addressAssociate($address_id,$instance_id)) { return false; } } // Attach volumes to this instance if(!empty($volumes)) { foreach($volumes as $volume_id) { if(!$this->Cloud->Volume->volumeMount($volume_id,$instance_id,false)) { return false; } } } $instance_ids = $this->removeElementFromArray($instance_id,$instance_ids); } } if(count($instance_ids) == 0) { $blocked = false; } else { sleep(10); } } // Ensure we have up-to-date instance data $this->getData(null,true); }