def get_cloud_params(self, keyname): """ Searches through the locations.json file with key 'infrastructure_info' to build a dict containing the parameters necessary to interact with Google Compute Engine. Args: keyname: A str that uniquely identifies this AppScale deployment. Returns: A dict containing all of the credentials necessary to interact with Google Compute Engine. """ params = { self.PARAM_GROUP : LocalState.get_group(keyname), self.PARAM_KEYNAME : keyname, self.PARAM_PROJECT : LocalState.get_project(keyname), self.PARAM_VERBOSE : False, # TODO(cgb): Don't put False in here. self.PARAM_ZONE : LocalState.get_zone(keyname) } if os.path.exists(LocalState.get_client_secrets_location(keyname)): params[self.PARAM_SECRETS] = \ LocalState.get_client_secrets_location(keyname) else: params[self.PARAM_STORAGE] = \ LocalState.get_oauth2_storage_location(keyname) return params
def open_connection(self, parameters): """ Connects to Google Compute Engine with the given credentials. Args: parameters: A dict that contains all the parameters necessary to authenticate this user with Google Compute Engine. We assume that the user has already authorized this account for use with GCE. Returns: An apiclient.discovery.Resource that is a connection valid for requests to Google Compute Engine for the given user, and a Credentials object that can be used to sign requests performed with that connection. Raises: AppScaleException if the user wants to abort. """ is_autoscale_agent = parameters.get(self.PARAM_AUTOSCALE_AGENT, False) # Determine paths to credential files if is_autoscale_agent: client_secrets_path = self.CLIENT_SECRETS_LOCATION oauth2_storage_path = self.OAUTH2_STORAGE_LOCATION else: # Determine client secrets path client_secrets_path = LocalState.get_client_secrets_location( parameters[self.PARAM_KEYNAME]) if not os.path.exists(client_secrets_path): client_secrets_path = parameters.get(self.PARAM_SECRETS, '') # Determine oauth2 storage oauth2_storage_path = parameters.get(self.PARAM_STORAGE) if not oauth2_storage_path or not os.path.exists(oauth2_storage_path): oauth2_storage_path = LocalState.get_oauth2_storage_location( parameters[self.PARAM_KEYNAME]) if os.path.exists(client_secrets_path): # Attempt to perform authorization using Service account secrets_type = GCEAgent.get_secrets_type(client_secrets_path) if secrets_type == CredentialTypes.SERVICE: scopes = [GCPScopes.COMPUTE] credentials = ServiceAccountCredentials.from_json_keyfile_name( client_secrets_path, scopes=scopes) return discovery.build('compute', self.API_VERSION), credentials # Perform authorization using OAuth2 storage storage = oauth2client.file.Storage(oauth2_storage_path) credentials = storage.get() if not credentials or credentials.invalid: # If we couldn't get valid credentials from OAuth2 storage if not os.path.exists(client_secrets_path): raise AgentConfigurationException( 'Couldn\'t find client secrets file at {}'.format(client_secrets_path) ) # Run OAuth2 flow to get credentials flow = oauth2client.client.flow_from_clientsecrets( client_secrets_path, scope=self.GCE_SCOPE) flags = oauth2client.tools.argparser.parse_args(args=[]) credentials = oauth2client.tools.run_flow(flow, storage, flags) # Build the service return discovery.build('compute', self.API_VERSION), credentials
def get_params_from_args(self, args): """ Constructs a dict with only the parameters necessary to interact with Google Compute Engine (here, the client_secrets file and the image name). Args: args: A Namespace or dict that maps all of the arguments the user has invoked an AppScale command with their associated value. Returns: A dict containing the location of the client_secrets file and that name of the image to use in GCE. Raises: AgentConfigurationException: If the caller fails to specify a client_secrets file, or if it doesn't exist on the local filesystem. """ if not isinstance(args, dict): args = vars(args) if not args.get('client_secrets') and not args.get('oauth2_storage'): raise AgentConfigurationException("Please specify a client_secrets " + \ "file or a oauth2_storage file in your AppScalefile when running " + \ "over Google Compute Engine.") credentials_file = args.get('client_secrets') or args.get('oauth2_storage') full_credentials = os.path.expanduser(credentials_file) if not os.path.exists(full_credentials): raise AgentConfigurationException("Couldn't find your credentials " + \ "at {0}".format(full_credentials)) if args.get('client_secrets'): destination = LocalState.get_client_secrets_location(args['keyname']) # Make sure the destination's parent directory exists. destination_par = os.path.abspath(os.path.join(destination, os.pardir)) if not os.path.exists(destination_par): os.makedirs(destination_par) shutil.copy(full_credentials, destination) elif args.get('oauth2_storage'): destination = LocalState.get_oauth2_storage_location(args['keyname']) # Make sure the destination's parent directory exists. destination_par = os.path.abspath(os.path.join(destination, os.pardir)) if not os.path.exists(destination_par): os.makedirs(destination_par) shutil.copy(full_credentials, destination) params = { self.PARAM_GROUP : args['group'], self.PARAM_IMAGE_ID : args['machine'], self.PARAM_INSTANCE_TYPE : args[self.PARAM_INSTANCE_TYPE], self.PARAM_KEYNAME : args['keyname'], self.PARAM_PROJECT : args['project'], self.PARAM_STATIC_IP : args.get(self.PARAM_STATIC_IP), self.PARAM_ZONE : args['zone'], self.PARAM_TEST: args['test'], } # A zone in GCE looks like 'us-central2-a', which is in the region # 'us-central2'. Therefore, strip off the last two characters from the zone # to get the region name. if params[self.PARAM_ZONE]: params[self.PARAM_REGION] = params[self.PARAM_ZONE][:-2] else: params[self.PARAM_REGION] = self.DEFAULT_REGION if args.get(self.PARAM_SECRETS): params[self.PARAM_SECRETS] = args.get(self.PARAM_SECRETS) elif args.get(self.PARAM_STORAGE): params[self.PARAM_STORAGE] = args.get(self.PARAM_STORAGE) params[self.PARAM_VERBOSE] = args.get('verbose', False) self.assert_credentials_are_valid(params) return params
def test_terminate_in_gce_and_succeeds(self): # let's say that there is a locations.json file with key # 'infrastructure_info', which means appscale is running, so we should # terminate the services on each box flexmock(os.path) os.path.should_call('exists') # set up the fall-through os.path.should_receive('exists').with_args( LocalState.get_client_secrets_location(self.keyname)).and_return(True) os.path.should_receive('exists').with_args( LocalState.get_secret_key_location(self.keyname)).and_return(True) # mock out reading the locations.json file with key # 'infrastructure_info', and pretend that we're on GCE project_id = "1234567890" zone = 'my-zone-1b' builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') # Assume persistent disks are used. flexmock(LocalState).should_receive('are_disks_used').and_return(True) # mock out reading the json file, and pretend that we're running in a # two node deployment os.path.should_receive('exists').with_args( LocalState.get_locations_json_location(self.keyname)).and_return(True) fake_json_file = flexmock(name='fake_file') fake_json_file.should_receive('read').and_return(json.dumps({ "infrastructure_info": { 'infrastructure': 'gce', 'group': self.group, 'project': project_id, 'zone': zone }, "node_info": [ { 'public_ip': 'public1', 'jobs': ['shadow'] }, { 'public_ip': 'public2', 'jobs': ['appengine'] } ] })) builtins.should_receive('open').with_args( LocalState.get_locations_json_location(self.keyname), 'r') \ .and_return(fake_json_file) # and slip in a fake secret file fake_secret_file = flexmock(name='fake_file') fake_secret_file.should_receive('read').and_return('the secret') builtins.should_receive('open').with_args( LocalState.get_secret_key_location(self.keyname), 'r') \ .and_return(fake_secret_file) # also add in a fake client-secrets file for GCE client_secrets = LocalState.get_client_secrets_location(self.keyname) # mock out talking to GCE # first, mock out the oauth library calls fake_flow = flexmock(name='fake_flow') flexmock(oauth2client.client) oauth2client.client.should_receive('flow_from_clientsecrets').with_args( client_secrets, scope=str).and_return(fake_flow) fake_storage = flexmock(name='fake_storage') fake_storage.should_receive('get').and_return(None) fake_flags = oauth2client.tools.argparser.parse_args(args=[]) flexmock(oauth2client.file) oauth2client.file.should_receive('Storage').with_args(str).and_return( fake_storage) fake_credentials = flexmock(name='fake_credentials') flexmock(oauth2client.tools) oauth2client.tools.should_receive('run_flow').with_args(fake_flow, fake_storage, fake_flags).and_return(fake_credentials) # next, mock out http calls to GCE fake_http = flexmock(name='fake_http') fake_authorized_http = flexmock(name='fake_authorized_http') flexmock(httplib2) httplib2.should_receive('Http').and_return(fake_http) fake_credentials.should_receive('authorize').with_args(fake_http) \ .and_return(fake_authorized_http) fake_gce = flexmock(name='fake_gce') # let's say that two instances are running instance_one_info = { u'status': u'RUNNING', u'kind': u'compute#instance', u'machineType': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/machineTypes/n1-standard-1', u'name': u'bazboogroup-one', u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'tags': {u'fingerprint': u'42WmSpB8rSM='}, u'image': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/images/lucid64', u'disks': [{ u'index': 0, u'kind': u'compute#attachedDisk', u'type': u'EPHEMERAL', u'mode': u'READ_WRITE' }], u'canIpForward': False, u'serviceAccounts': [{ u'scopes': [GCEAgent.GCE_SCOPE], u'email': u'*****@*****.**' }], u'metadata': { u'kind': u'compute#metadata', u'fingerprint': u'42WmSpB8rSM=' }, u'creationTimestamp': u'2013-05-22T11:52:33.254-07:00', u'id': u'8684033495853907982', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/bazboogroup-feb10b11-62bc-4536-ac25-9734f2267d6d', u'networkInterfaces': [{ u'accessConfigs': [{ u'kind': u'compute#accessConfig', u'type': u'ONE_TO_ONE_NAT', u'name': u'External NAT', u'natIP': u'public1' }], u'networkIP': u'private1', u'network': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazboogroup', u'name': u'nic0' }] } instance_two_info = { u'status': u'RUNNING', u'kind': u'compute#instance', u'machineType': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/machineTypes/n1-standard-1', u'name': u'bazboogroup-two', u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'tags': {u'fingerprint': u'42WmSpB8rSM='}, u'image': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/images/lucid64', u'disks': [{ u'index': 0, u'kind': u'compute#attachedDisk', u'type': u'EPHEMERAL', u'mode': u'READ_WRITE' }], u'canIpForward': False, u'serviceAccounts': [{ u'scopes': [GCEAgent.GCE_SCOPE], u'email': u'*****@*****.**' }], u'metadata': { u'kind': u'compute#metadata', u'fingerprint': u'42WmSpB8rSM=' }, u'creationTimestamp': u'2013-05-22T11:52:33.254-07:00', u'id': u'8684033495853907982', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/bazboogroup-feb10b11-62bc-4536-ac25-9734f2267d6d', u'networkInterfaces': [{ u'accessConfigs': [{ u'kind': u'compute#accessConfig', u'type': u'ONE_TO_ONE_NAT', u'name': u'External NAT', u'natIP': u'public1' }], u'networkIP': u'private1', u'network': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazboogroup', u'name': u'nic0' }] } list_instance_info = { u'items': [instance_one_info, instance_two_info], u'kind': u'compute#instanceList', u'id': u'projects/appscale.com:appscale/zones/my-zone-1b/instances', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/961228229472/zones/my-zone-1b/instances' } fake_list_instance_request = flexmock(name='fake_list_instance_request') fake_list_instance_request.should_receive('execute').with_args( http=fake_authorized_http).and_return(list_instance_info) fake_instances = flexmock(name='fake_instances') fake_instances.should_receive('list').with_args(project=project_id, filter="name eq bazboogroup-.*", zone=zone) \ .and_return(fake_list_instance_request) fake_gce.should_receive('instances').and_return(fake_instances) # And assume that we can kill both of our instances fine delete_instance = u'operation-1369676691806-4ddb6b4ab6f39-a095d3de' delete_instance_info_one = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_instance, u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'startTime': u'2013-05-27T10:44:51.849-07:00', u'insertTime': u'2013-05-27T10:44:51.806-07:00', u'targetId': u'12912855597472179535', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/appscalecgb20-0cf89267-5887-4048-b774-ca20de47a07f', u'operationType': u'delete', u'progress': 0, u'id': u'11114355109942058217', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/operations/operation-1369676691806-4ddb6b4ab6f39-a095d3de', u'user': u'*****@*****.**' } delete_instance_info_two = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_instance, u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'startTime': u'2013-05-27T10:44:51.849-07:00', u'insertTime': u'2013-05-27T10:44:51.806-07:00', u'targetId': u'12912855597472179535', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/appscalecgb20-0cf89267-5887-4048-b774-ca20de47a07f', u'operationType': u'delete', u'progress': 0, u'id': u'11114355109942058217', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/operations/operation-1369676691806-4ddb6b4ab6f39-a095d3de', u'user': u'*****@*****.**' } fake_delete_instance_request_one = flexmock(name='fake_delete_instance_request_one') fake_delete_instance_request_one.should_receive('execute').with_args( http=fake_authorized_http).and_return(delete_instance_info_one) fake_instances.should_receive('delete').with_args(project=project_id, zone=zone, instance='bazboogroup-one').and_return( fake_delete_instance_request_one) fake_delete_instance_request_two = flexmock(name='fake_delete_instance_request_two') fake_delete_instance_request_two.should_receive('execute').with_args( http=fake_authorized_http).and_return(delete_instance_info_two) fake_instances.should_receive('delete').with_args(project=project_id, zone=zone, instance='bazboogroup-two').and_return( fake_delete_instance_request_two) # mock out our waiting for the instances to be deleted all_done = { u'status' : u'DONE' } fake_instance_checker = flexmock(name='fake_instance_checker') fake_instance_checker.should_receive('execute').and_return(all_done) fake_blocker = flexmock(name='fake_blocker') fake_blocker.should_receive('get').with_args(project=project_id, operation=delete_instance, zone=zone).and_return( fake_instance_checker) fake_gce.should_receive('zoneOperations').and_return(fake_blocker) # mock out the call to delete the firewall delete_firewall = u'operation-1369677695390-4ddb6f07cc611-5a8f1654' fake_delete_firewall_info = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_firewall, u'startTime': u'2013-05-27T11:01:35.482-07:00', u'insertTime': u'2013-05-27T11:01:35.390-07:00', u'targetId': u'11748720697396371259', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/firewalls/appscalecgb20', u'operationType': u'delete', u'progress': 0, u'id': u'15574488986772298961', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/operations/operation-1369677695390-4ddb6f07cc611-5a8f1654', u'user': u'*****@*****.**' } fake_delete_firewall_request = flexmock(name='fake_delete_firewall_request') fake_delete_firewall_request.should_receive('execute').and_return(fake_delete_firewall_info) fake_firewalls = flexmock(name='fake_firewalls') fake_firewalls.should_receive('delete').with_args(project=project_id, firewall=self.group).and_return(fake_delete_firewall_request) fake_gce.should_receive('firewalls').and_return(fake_firewalls) # mock out the call to make sure the firewall was deleted fake_firewall_checker = flexmock(name='fake_firewall_checker') fake_firewall_checker.should_receive('execute').and_return(all_done) fake_blocker.should_receive('get').with_args(project=project_id, operation=delete_firewall).and_return(fake_firewall_checker) fake_gce.should_receive('globalOperations').and_return(fake_blocker) # and the call to delete the network delete_network = u'operation-1369677749954-4ddb6f3bd1849-056cf8ca' fake_delete_network_info = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_network, u'startTime': u'2013-05-27T11:02:30.012-07:00', u'insertTime': u'2013-05-27T11:02:29.954-07:00', u'targetId': u'17688075350400527692', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/appscalecgb20', u'operationType': u'delete', u'progress': 0, u'id': u'12623697331874594836', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/operations/operation-1369677749954-4ddb6f3bd1849-056cf8ca', u'user': u'*****@*****.**' } fake_delete_network_request = flexmock(name='fake_delete_network_request') fake_delete_network_request.should_receive('execute').and_return(fake_delete_network_info) fake_networks = flexmock(name='fake_networks') fake_networks.should_receive('delete').with_args(project=project_id, network=self.group).and_return(fake_delete_network_request) fake_gce.should_receive('networks').and_return(fake_networks) # mock out the call to make sure the network was deleted fake_network_checker = flexmock(name='fake_network_checker') fake_network_checker.should_receive('execute').and_return(all_done) fake_blocker.should_receive('get').with_args(project=project_id, operation=delete_network).and_return(fake_network_checker) # finally, inject our fake GCE connection flexmock(apiclient.discovery) apiclient.discovery.should_receive('build').with_args('compute', GCEAgent.API_VERSION).and_return(fake_gce) flexmock(GCEAgent).should_receive('get_secrets_type')\ .and_return(CredentialTypes.OAUTH) # finally, mock out removing the yaml file, json file, and secret key from # this machine flexmock(os) os.should_receive('remove').with_args( LocalState.get_locations_json_location(self.keyname)).and_return() os.should_receive('remove').with_args( LocalState.get_secret_key_location(self.keyname)).and_return() flexmock(RemoteHelper).should_receive('terminate_cloud_infrastructure') argv = [ "--keyname", self.keyname, "--test" ] options = ParseArgs(argv, self.function).args AppScaleTools.terminate_instances(options)
def test_terminate_in_gce_and_succeeds(self): # let's say that there is a locations.json file with key # 'infrastructure_info', which means appscale is running, so we should # terminate the services on each box flexmock(os.path) os.path.should_call('exists') # set up the fall-through os.path.should_receive('exists').with_args( LocalState.get_client_secrets_location( self.keyname)).and_return(True) os.path.should_receive('exists').with_args( LocalState.get_secret_key_location(self.keyname)).and_return(True) # mock out reading the locations.json file with key # 'infrastructure_info', and pretend that we're on GCE project_id = "1234567890" zone = 'my-zone-1b' builtins = flexmock(sys.modules['__builtin__']) builtins.should_call('open') # Assume persistent disks are used. flexmock(LocalState).should_receive('are_disks_used').and_return(True) # mock out reading the json file, and pretend that we're running in a # two node deployment os.path.should_receive('exists').with_args( LocalState.get_locations_json_location( self.keyname)).and_return(True) fake_json_file = flexmock(name='fake_file') fake_json_file.should_receive('read').and_return( json.dumps({ "infrastructure_info": { 'infrastructure': 'gce', 'group': self.group, 'project': project_id, 'zone': zone }, "node_info": [{ 'public_ip': 'public1', 'jobs': ['shadow'] }, { 'public_ip': 'public2', 'jobs': ['appengine'] }] })) builtins.should_receive('open').with_args( LocalState.get_locations_json_location(self.keyname), 'r') \ .and_return(fake_json_file) # and slip in a fake secret file fake_secret_file = flexmock(name='fake_file') fake_secret_file.should_receive('read').and_return('the secret') builtins.should_receive('open').with_args( LocalState.get_secret_key_location(self.keyname), 'r') \ .and_return(fake_secret_file) # also add in a fake client-secrets file for GCE client_secrets = LocalState.get_client_secrets_location(self.keyname) # mock out talking to GCE # first, mock out the oauth library calls fake_flow = flexmock(name='fake_flow') flexmock(oauth2client.client) oauth2client.client.should_receive( 'flow_from_clientsecrets').with_args( client_secrets, scope=str).and_return(fake_flow) fake_storage = flexmock(name='fake_storage') fake_storage.should_receive('get').and_return(None) fake_flags = oauth2client.tools.argparser.parse_args(args=[]) flexmock(oauth2client.file) oauth2client.file.should_receive('Storage').with_args(str).and_return( fake_storage) fake_credentials = flexmock(name='fake_credentials') flexmock(oauth2client.tools) oauth2client.tools.should_receive('run_flow').with_args( fake_flow, fake_storage, fake_flags).and_return(fake_credentials) # next, mock out http calls to GCE fake_http = flexmock(name='fake_http') fake_authorized_http = flexmock(name='fake_authorized_http') flexmock(httplib2) httplib2.should_receive('Http').and_return(fake_http) fake_credentials.should_receive('authorize').with_args(fake_http) \ .and_return(fake_authorized_http) fake_gce = flexmock(name='fake_gce') # let's say that two instances are running instance_one_info = { u'status': u'RUNNING', u'kind': u'compute#instance', u'machineType': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/machineTypes/n1-standard-1', u'name': u'bazboogroup-one', u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'tags': { u'fingerprint': u'42WmSpB8rSM=' }, u'image': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/images/lucid64', u'disks': [{ u'index': 0, u'kind': u'compute#attachedDisk', u'type': u'EPHEMERAL', u'mode': u'READ_WRITE' }], u'canIpForward': False, u'serviceAccounts': [{ u'scopes': [GCEAgent.GCE_SCOPE], u'email': u'*****@*****.**' }], u'metadata': { u'kind': u'compute#metadata', u'fingerprint': u'42WmSpB8rSM=' }, u'creationTimestamp': u'2013-05-22T11:52:33.254-07:00', u'id': u'8684033495853907982', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/bazboogroup-feb10b11-62bc-4536-ac25-9734f2267d6d', u'networkInterfaces': [{ u'accessConfigs': [{ u'kind': u'compute#accessConfig', u'type': u'ONE_TO_ONE_NAT', u'name': u'External NAT', u'natIP': u'public1' }], u'networkIP': u'private1', u'network': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazboogroup', u'name': u'nic0' }] } instance_two_info = { u'status': u'RUNNING', u'kind': u'compute#instance', u'machineType': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/machineTypes/n1-standard-1', u'name': u'bazboogroup-two', u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'tags': { u'fingerprint': u'42WmSpB8rSM=' }, u'image': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/images/lucid64', u'disks': [{ u'index': 0, u'kind': u'compute#attachedDisk', u'type': u'EPHEMERAL', u'mode': u'READ_WRITE' }], u'canIpForward': False, u'serviceAccounts': [{ u'scopes': [GCEAgent.GCE_SCOPE], u'email': u'*****@*****.**' }], u'metadata': { u'kind': u'compute#metadata', u'fingerprint': u'42WmSpB8rSM=' }, u'creationTimestamp': u'2013-05-22T11:52:33.254-07:00', u'id': u'8684033495853907982', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/bazboogroup-feb10b11-62bc-4536-ac25-9734f2267d6d', u'networkInterfaces': [{ u'accessConfigs': [{ u'kind': u'compute#accessConfig', u'type': u'ONE_TO_ONE_NAT', u'name': u'External NAT', u'natIP': u'public1' }], u'networkIP': u'private1', u'network': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazboogroup', u'name': u'nic0' }] } list_instance_info = { u'items': [instance_one_info, instance_two_info], u'kind': u'compute#instanceList', u'id': u'projects/appscale.com:appscale/zones/my-zone-1b/instances', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/961228229472/zones/my-zone-1b/instances' } fake_list_instance_request = flexmock( name='fake_list_instance_request') fake_list_instance_request.should_receive('execute').with_args( http=fake_authorized_http).and_return(list_instance_info) fake_instances = flexmock(name='fake_instances') fake_instances.should_receive('list').with_args(project=project_id, filter="name eq bazboogroup-.*", zone=zone) \ .and_return(fake_list_instance_request) fake_gce.should_receive('instances').and_return(fake_instances) # And assume that we can kill both of our instances fine delete_instance = u'operation-1369676691806-4ddb6b4ab6f39-a095d3de' delete_instance_info_one = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_instance, u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'startTime': u'2013-05-27T10:44:51.849-07:00', u'insertTime': u'2013-05-27T10:44:51.806-07:00', u'targetId': u'12912855597472179535', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/appscalecgb20-0cf89267-5887-4048-b774-ca20de47a07f', u'operationType': u'delete', u'progress': 0, u'id': u'11114355109942058217', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/operations/operation-1369676691806-4ddb6b4ab6f39-a095d3de', u'user': u'*****@*****.**' } delete_instance_info_two = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_instance, u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b', u'startTime': u'2013-05-27T10:44:51.849-07:00', u'insertTime': u'2013-05-27T10:44:51.806-07:00', u'targetId': u'12912855597472179535', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/instances/appscalecgb20-0cf89267-5887-4048-b774-ca20de47a07f', u'operationType': u'delete', u'progress': 0, u'id': u'11114355109942058217', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/my-zone-1b/operations/operation-1369676691806-4ddb6b4ab6f39-a095d3de', u'user': u'*****@*****.**' } fake_delete_instance_request_one = flexmock( name='fake_delete_instance_request_one') fake_delete_instance_request_one.should_receive('execute').with_args( http=fake_authorized_http).and_return(delete_instance_info_one) fake_instances.should_receive('delete').with_args( project=project_id, zone=zone, instance='bazboogroup-one').and_return( fake_delete_instance_request_one) fake_delete_instance_request_two = flexmock( name='fake_delete_instance_request_two') fake_delete_instance_request_two.should_receive('execute').with_args( http=fake_authorized_http).and_return(delete_instance_info_two) fake_instances.should_receive('delete').with_args( project=project_id, zone=zone, instance='bazboogroup-two').and_return( fake_delete_instance_request_two) # mock out our waiting for the instances to be deleted all_done = {u'status': u'DONE'} fake_instance_checker = flexmock(name='fake_instance_checker') fake_instance_checker.should_receive('execute').and_return(all_done) fake_blocker = flexmock(name='fake_blocker') fake_blocker.should_receive('get').with_args( project=project_id, operation=delete_instance, zone=zone).and_return(fake_instance_checker) fake_gce.should_receive('zoneOperations').and_return(fake_blocker) # mock out the call to delete the firewall delete_firewall = u'operation-1369677695390-4ddb6f07cc611-5a8f1654' fake_delete_firewall_info = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_firewall, u'startTime': u'2013-05-27T11:01:35.482-07:00', u'insertTime': u'2013-05-27T11:01:35.390-07:00', u'targetId': u'11748720697396371259', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/firewalls/appscalecgb20', u'operationType': u'delete', u'progress': 0, u'id': u'15574488986772298961', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/operations/operation-1369677695390-4ddb6f07cc611-5a8f1654', u'user': u'*****@*****.**' } fake_delete_firewall_request = flexmock( name='fake_delete_firewall_request') fake_delete_firewall_request.should_receive('execute').and_return( fake_delete_firewall_info) fake_firewalls = flexmock(name='fake_firewalls') fake_firewalls.should_receive('delete').with_args( project=project_id, firewall=self.group).and_return(fake_delete_firewall_request) fake_gce.should_receive('firewalls').and_return(fake_firewalls) # mock out the call to make sure the firewall was deleted fake_firewall_checker = flexmock(name='fake_firewall_checker') fake_firewall_checker.should_receive('execute').and_return(all_done) fake_blocker.should_receive('get').with_args( project=project_id, operation=delete_firewall).and_return(fake_firewall_checker) fake_gce.should_receive('globalOperations').and_return(fake_blocker) # and the call to delete the network delete_network = u'operation-1369677749954-4ddb6f3bd1849-056cf8ca' fake_delete_network_info = { u'status': u'PENDING', u'kind': u'compute#operation', u'name': delete_network, u'startTime': u'2013-05-27T11:02:30.012-07:00', u'insertTime': u'2013-05-27T11:02:29.954-07:00', u'targetId': u'17688075350400527692', u'targetLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/appscalecgb20', u'operationType': u'delete', u'progress': 0, u'id': u'12623697331874594836', u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/operations/operation-1369677749954-4ddb6f3bd1849-056cf8ca', u'user': u'*****@*****.**' } fake_delete_network_request = flexmock( name='fake_delete_network_request') fake_delete_network_request.should_receive('execute').and_return( fake_delete_network_info) fake_networks = flexmock(name='fake_networks') fake_networks.should_receive('delete').with_args( project=project_id, network=self.group).and_return(fake_delete_network_request) fake_gce.should_receive('networks').and_return(fake_networks) # mock out the call to make sure the network was deleted fake_network_checker = flexmock(name='fake_network_checker') fake_network_checker.should_receive('execute').and_return(all_done) fake_blocker.should_receive('get').with_args( project=project_id, operation=delete_network).and_return(fake_network_checker) # finally, inject our fake GCE connection flexmock(apiclient.discovery) apiclient.discovery.should_receive('build').with_args( 'compute', GCEAgent.API_VERSION).and_return(fake_gce) flexmock(GCEAgent).should_receive('get_secrets_type')\ .and_return(CredentialTypes.OAUTH) # finally, mock out removing the yaml file, json file, and secret key from # this machine flexmock(os) os.should_receive('remove').with_args( LocalState.get_locations_json_location(self.keyname)).and_return() os.should_receive('remove').with_args( LocalState.get_secret_key_location(self.keyname)).and_return() flexmock(RemoteHelper).should_receive('terminate_cloud_infrastructure') argv = ["--keyname", self.keyname, "--test"] options = ParseArgs(argv, self.function).args AppScaleTools.terminate_instances(options)