예제 #1
0
  def test_attach_persistent_disk(self):
    # mock out interactions with GCE
    # first, mock out the oauth library calls
    fake_credentials = flexmock(name='fake_credentials')
    fake_credentials.should_receive('invalid').and_return(False)
    fake_storage = flexmock(name='fake_storage')
    fake_storage.should_receive('get').and_return(fake_credentials)

    flexmock(oauth2client.file)
    oauth2client.file.should_receive('Storage').with_args(
      GCEAgent.OAUTH2_STORAGE_LOCATION).and_return(fake_storage)

    # 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_instances = flexmock(name='fake_instances')
    fake_gce = flexmock(name='fake_gce')
    fake_gce.should_receive('instances').and_return(fake_instances)

    fake_attach_disk_request = flexmock(name='fake_attach_disk_request')
    fake_instances.should_receive('get').and_return(fake_attach_disk_request)

    attach_disk_info = {
      'status': 'DONE',
      'disks': []
    }

    fake_attach_disk_request.should_receive('execute').with_args(
      fake_authorized_http).and_return(attach_disk_info)

    fake_instances.should_receive('attachDisk').with_args(project=self.project,
      body=dict, instance='my-instance', zone=str).and_return(
      fake_attach_disk_request)

    # finally, inject our fake GCE connection
    flexmock(discovery)
    discovery.should_receive('build').with_args('compute',
      GCEAgent.API_VERSION).and_return(fake_gce)

    iaas = InfrastructureManager(blocking=True)
    disk_name = 'my-disk-name'
    instance_id = 'my-instance'
    expected = '/dev/sdb'
    actual = iaas.attach_disk(self.params, disk_name, instance_id, 'secret')
    self.assertTrue(actual['success'])
    self.assertEquals(expected, actual['location'])
예제 #2
0
  def test_attach_persistent_disk(self):
    # mock out interactions with GCE
    # first, mock out the oauth library calls
    fake_credentials = flexmock(name='fake_credentials', invalid=False)
    fake_storage = flexmock(name='fake_storage')
    fake_storage.should_receive('get').and_return(fake_credentials)

    flexmock(oauth2client.file)
    oauth2client.file.should_receive('Storage').with_args(
      GCEAgent.OAUTH2_STORAGE_LOCATION).and_return(fake_storage)

    # 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_instances = flexmock(name='fake_instances')
    fake_gce = flexmock(name='fake_gce')
    fake_gce.should_receive('instances').and_return(fake_instances)

    fake_attach_disk_request = flexmock(name='fake_attach_disk_request')
    fake_instances.should_receive('get').and_return(fake_attach_disk_request)

    attach_disk_info = {
      'status': 'DONE',
      'disks': []
    }

    fake_attach_disk_request.should_receive('execute').with_args(
      fake_authorized_http).and_return(attach_disk_info)

    fake_instances.should_receive('attachDisk').with_args(project=self.project,
      body=dict, instance='my-instance', zone=str).and_return(
      fake_attach_disk_request)

    # finally, inject our fake GCE connection
    flexmock(discovery)
    discovery.should_receive('build').with_args('compute',
      GCEAgent.API_VERSION).and_return(fake_gce)

    iaas = InfrastructureManager(blocking=True)
    disk_name = 'my-disk-name'
    instance_id = 'my-instance'
    expected = '/dev/sdb'
    actual = iaas.attach_disk(self.params, disk_name, instance_id, 'secret')
    self.assertTrue(actual['success'])
    self.assertEquals(expected, actual['location'])
예제 #3
0
    def test_attach_persistent_disk(self):
        # mock out interactions with GCE
        # first, mock out the oauth library calls
        fake_credentials = flexmock(name="fake_credentials")
        fake_storage = flexmock(name="fake_storage")
        fake_storage.should_receive("get").and_return(fake_credentials)

        flexmock(oauth2client.file)
        oauth2client.file.should_receive("Storage").with_args(GCEAgent.OAUTH2_STORAGE_LOCATION).and_return(fake_storage)

        # 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_instances = flexmock(name="fake_instances")
        fake_gce = flexmock(name="fake_gce")
        fake_gce.should_receive("instances").and_return(fake_instances)

        attach_disk_info = {"status": "DONE"}

        fake_attach_disk_request = flexmock(name="fake_attach_disk_request")
        fake_attach_disk_request.should_receive("execute").with_args(fake_authorized_http).and_return(attach_disk_info)

        fake_instances.should_receive("attachDisk").with_args(
            project=self.project, body=dict, instance="my-instance", zone=str
        ).and_return(fake_attach_disk_request)

        # finally, inject our fake GCE connection
        flexmock(apiclient.discovery)
        apiclient.discovery.should_receive("build").with_args("compute", GCEAgent.API_VERSION).and_return(fake_gce)

        iaas = InfrastructureManager(blocking=True)
        disk_name = "my-disk-name"
        instance_id = "my-instance"
        expected = "/dev/sdb"
        actual = iaas.attach_disk(self.params, disk_name, instance_id, "secret")
        self.assertTrue(actual["success"])
        self.assertEquals(expected, actual["location"])
예제 #4
0
  def test_gce_run_instances(self):
    # mock out interactions with GCE
    # first, mock out the oauth library calls
    fake_credentials = flexmock(name='fake_credentials')
    fake_credentials.should_receive('invalid').and_return(False)
    fake_storage = flexmock(name='fake_storage')
    fake_storage.should_receive('get').and_return(fake_credentials)

    flexmock(oauth2client.file)
    oauth2client.file.should_receive('Storage').with_args(
      GCEAgent.OAUTH2_STORAGE_LOCATION).and_return(fake_storage)

    # 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)

    # add some fake data in where no instances are initially running, then one
    # is (in response to our insert request)
    no_instance_info = {
    }

    instance_id = u'appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d'
    list_instance_info = {
      u'items': [{
        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': instance_id,
        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/appscale-bazgroup-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'public-ip'
          }],
          u'networkIP': u'private-ip',
          u'network': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazgroup',
          u'name': u'nic0'
        }]
      }],
      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(no_instance_info).and_return(list_instance_info)

    fake_instances = flexmock(name='fake_instances')
    fake_gce = flexmock(name='fake_gce')
    fake_gce.should_receive('instances').and_return(fake_instances)
    fake_instances.should_receive('list').with_args(project=self.project,
      filter="name eq boogroup-.*", zone='my-zone-1b') \
      .and_return(fake_list_instance_request)

    # we only need to create one node, so set up mocks for that
    add_instance = u'operation-1369248752891-4dd5311848461-afc55a20'
    add_instance_info = {
      u'status': u'PENDING',
      u'kind': u'compute#operation',
      u'name': add_instance,
      u'azone': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/my-zone-1b',
      u'startTime': u'2013-05-22T11:52:32.939-07:00',
      u'insertTime': u'2013-05-22T11:52:32.891-07:00',
      u'targetLink': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/my-zone-1b/instances/appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d',
      u'operationType': u'insert',
      u'progress': 0,
      u'id': u'6663616273628949255',
      u'selfLink': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/my-zone-1b/operations/operation-1369248752891-4dd5311848461-afc55a20',
      u'user': u'*****@*****.**'
    }

    fake_add_instance_request = flexmock(name='fake_add_instance_request')
    fake_add_instance_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(add_instance_info)

    fake_instances.should_receive('insert').with_args(project=self.project,
      body=dict, zone=str).and_return(fake_add_instance_request)

    created_instance_info = {
      u'status': u'DONE'
    }

    fake_instance_checker = flexmock(name='fake_network_checker')
    fake_instance_checker.should_receive('execute').and_return(
      created_instance_info)

    fake_blocker = flexmock(name='fake_blocker')
    fake_gce.should_receive('globalOperations').and_return(fake_blocker)
    fake_blocker.should_receive('get').with_args(project=self.project,
      operation=add_instance).and_return(fake_instance_checker)

    # finally, inject our fake GCE connection
    flexmock(discovery)
    discovery.should_receive('build').with_args('compute',
      GCEAgent.API_VERSION).and_return(fake_gce)

    # next, presume that the persistent disk we want to use exists
    disk_name = 'my-persistent-disk-1'
    disk_info = {'status':'DONE'}
    fake_disk_request = flexmock(name='fake_disk_request')
    fake_disk_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(disk_info)

    fake_disks = flexmock(name='fake_disks')
    fake_disks.should_receive('get').with_args(project=self.project,
      disk=disk_name, zone=str).and_return(fake_disk_request)
    fake_disks.should_receive('insert').with_args(project=self.project,
      sourceImage=str, body=dict, zone=str).and_return(fake_disk_request)

    fake_gce.should_receive('disks').and_return(fake_disks)

    public_key = 'ssh-rsa long_key_string'
    flexmock(utils).should_receive('get_public_key').and_return(public_key)

    i = InfrastructureManager(blocking=True)

    # first, validate that the run_instances call goes through successfully
    # and gives the user a reservation id
    full_result = {
      'success': True,
      'reservation_id': self.reservation_id,
      'reason': 'none'
    }
    self.assertEquals(full_result, i.run_instances(self.params, 'secret'))

    # next, look at run_instances internally to make sure it actually is
    # updating its reservation info
    self.assertEquals(InfrastructureManager.STATE_RUNNING, i.reservations.get(
      self.reservation_id)['state'])
    vm_info = i.reservations.get(self.reservation_id)['vm_info']
    self.assertEquals(['public-ip'], vm_info['public_ips'])
    self.assertEquals(['private-ip'], vm_info['private_ips'])
    self.assertEquals([instance_id], vm_info['instance_ids'])
  def test_appscale_in_one_node_gce_deployment(self):
    # presume that our client_secrets file exists
    project_id = "appscale.com:appscale"
    client_secrets = "/boo/client_secrets.json"
    instance_type = 'n1-standard-8'
    zone = 'my-zone1-b'
    os.path.should_receive('exists').with_args(client_secrets).and_return(True)

    # and that the user does not have an ssh key set up, forcing us to create
    # one for them
    private_key = '{0}{1}.key'.format(LocalState.LOCAL_APPSCALE_PATH,
      self.keyname)
    public_key = '{0}{1}.pub'.format(LocalState.LOCAL_APPSCALE_PATH,
      self.keyname)

    os.path.should_receive('exists').with_args(private_key).and_return(False)
    os.path.should_receive('exists').with_args(public_key).and_return(False)

    self.local_state.should_receive('shell').with_args(re.compile('^ssh-keygen'), False).and_return()

    flexmock(os)
    original_private_key = LocalState.LOCAL_APPSCALE_PATH + self.keyname
    os.should_receive('chmod').with_args(original_private_key, 0600)
    os.should_receive('chmod').with_args(public_key, 0600)

    flexmock(shutil)
    shutil.should_receive('copy').with_args(original_private_key, private_key)

    # also, we should be able to copy over our secret.json file fine
    shutil.should_receive('copy').with_args(client_secrets,
      LocalState.get_client_secrets_location(self.keyname))

    # let's say that appscale isn't already running
    self.local_state.should_receive('ensure_appscale_isnt_running').and_return()
    self.local_state.should_receive('make_appscale_directory').and_return()

    # mock out talking to logs.appscale.com
    fake_connection = flexmock(name='fake_connection')
    fake_connection.should_receive('request').with_args('POST', '/upload', str,
      AppScaleLogger.HEADERS).and_return()

    flexmock(httplib)
    httplib.should_receive('HTTPConnection').with_args('logs.appscale.com') \
      .and_return(fake_connection)

    # mock out generating the secret key
    flexmock(uuid)
    uuid.should_receive('uuid4').and_return('the secret')

    # mock out writing the secret key to ~/.appscale, as well as reading it
    # later
    secret_key_location = LocalState.get_secret_key_location(self.keyname)
    fake_secret = flexmock(name="fake_secret")
    fake_secret.should_receive('read').and_return('the secret')
    fake_secret.should_receive('write').and_return()
    self.builtins.should_receive('open').with_args(secret_key_location, 'r') \
      .and_return(fake_secret)
    self.builtins.should_receive('open').with_args(secret_key_location, 'w') \
      .and_return(fake_secret)

    # mock out interactions with 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)

    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').with_args(fake_flow,
      fake_storage).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)

    # presume that there is an ssh key stored, but it isn't ours
    metadata_info = {
      u'kind': u'compute#project', 
      u'description': u'', 
      u'commonInstanceMetadata': {
        u'items': [{
          u'value': u'cgb:ssh-rsa keyinfo myhost', 
          u'key': u'sshKeys'}], 
        u'kind': u'compute#metadata'},
    }
    fake_metadata_request = flexmock(name='fake_metadata_request')
    fake_metadata_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(metadata_info)

    fake_projects = flexmock(name='fake_projects')
    fake_projects.should_receive('get').with_args(project=project_id) \
      .and_return(fake_metadata_request)

    fake_gce = flexmock(name='fake_gce')
    fake_gce.should_receive('projects').and_return(fake_projects)

    # thus we will need to set the metadata with our ssh key
    fake_ssh_pub_key = flexmock(name="fake_ssh_pub_key")
    fake_ssh_pub_key.should_receive('read').and_return('ssh-rsa key2info myhost')
    self.builtins.should_receive('open').with_args(public_key).and_return(
      fake_ssh_pub_key)

    new_metadata_body = {
      "items": [{
        "value" : u'cgb:ssh-rsa key2info myhost\ncgb:ssh-rsa keyinfo myhost',
        "key" : "sshKeys"
      }],
      "kind": "compute#metadata"
    }

    set_metadata_name = u'operation-222222-4dd41ec7d6c11-8013657f'
    set_metadata = {
      u'status': u'PENDING',
      u'kind': u'compute#operation',
      u'name': set_metadata_name,
      u'operationType': u'insert',
      u'progress': 0,
      u'selfLink': unicode(GCEAgent.GCE_URL) + \
        u'appscale.com:appscale/global/operations/' + \
        u'operation-1369175117235-4dd41ec7d6c11-8013657f',
      u'user': u'*****@*****.**'
    }

    fake_set_metadata_request = flexmock(name='fake_set_metadata_request')
    fake_set_metadata_request.should_receive('execute').and_return(set_metadata)

    fake_projects.should_receive('setCommonInstanceMetadata').with_args(
      project=project_id, body=dict).and_return(fake_set_metadata_request)

    updated_metadata_info = {
      u'status': u'DONE'
    }

    fake_metadata_checker = flexmock(name='fake_network_checker')
    fake_metadata_checker.should_receive('execute').and_return(
      updated_metadata_info)
    fake_blocker = flexmock(name='fake_blocker')
    fake_blocker.should_receive('get').with_args(project=project_id,
      operation=set_metadata_name).and_return(fake_metadata_checker)

    # presume that our image does exist in GCE, with some fake data
    # acquired by running a not mocked version of this code
    image_name = 'appscale-image-name'
    image_info = {
      u'kind': u'compute#image',
      u'description': u'',
      u'rawDisk': {u'containerType': u'TAR', u'source': u''},
      u'preferredKernel': unicode(GCEAgent.GCE_URL) + \
        u'/google/global/kernels/gce-v20130515',
      u'sourceType': u'RAW',
      u'creationTimestamp': u'2013-05-21T08:05:12.198-07:00',
      u'id': u'4235320207849085220',
      u'selfLink': unicode(GCEAgent.GCE_URL) + \
        u'961228229472/global/images/' + unicode(image_name),
      u'name': unicode(image_name)
    }
    fake_image_request = flexmock(name='fake_image_request')
    fake_image_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(image_info)

    fake_images = flexmock(name='fake_images')
    fake_images.should_receive('get').with_args(project=project_id,
      image=image_name).and_return(fake_image_request)

    fake_gce.should_receive('images').and_return(fake_images)

    # next, presume that the static ip we want to use exists
    address_name = 'static-ip'
    address_info = {'items':[]}
    region_name = 'my-zone1'
    fake_address_request = flexmock(name='fake_address_request')
    fake_address_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(address_info)

    fake_addresses = flexmock(name='fake_addresses')
    fake_addresses.should_receive('list').with_args(project=project_id,
      filter="address eq static-ip", region=region_name).and_return(
      fake_address_request)

    fake_gce.should_receive('addresses').and_return(fake_addresses)

    # next, presume that the zone we want to use exists
    zone_name = 'my-zone1-b'
    zone_info = {}
    fake_zone_request = flexmock(name='fake_zone_request')
    fake_zone_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(zone_info)

    fake_zones = flexmock(name='fake_zones')
    fake_zones.should_receive('get').with_args(project=project_id,
      zone=zone_name).and_return(fake_zone_request)

    fake_gce.should_receive('zones').and_return(fake_zones)

    # next, presume that the persistent disk we want to use exists
    disk_name = 'my-persistent-disk-1'
    disk_info = {'status':'DONE'}
    fake_disk_request = flexmock(name='fake_disk_request')
    fake_disk_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(disk_info)

    fake_disks = flexmock(name='fake_disks')
    fake_disks.should_receive('get').with_args(project=project_id,
      disk=disk_name, zone=zone).and_return(fake_disk_request)
    fake_disks.should_receive('insert').with_args(project=project_id,
      sourceImage=str, body=dict, zone=zone_name).and_return(fake_disk_request)

    fake_gce.should_receive('disks').and_return(fake_disks)

    # next, presume that the network doesn't exist yet
    fake_network_request = flexmock(name='fake_network_request')
    fake_network_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_raise(apiclient.errors.HttpError, None,
      None)

    fake_networks = flexmock(name='fake_networks')
    fake_networks.should_receive('get').with_args(project=project_id,
      network='bazgroup').and_return(fake_network_request)
    fake_gce.should_receive('networks').and_return(fake_networks)

    # next, presume that the firewall doesn't exist yet
    fake_firewall_request = flexmock(name='fake_firewall_request')
    fake_firewall_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_raise(apiclient.errors.HttpError, None,
      None)

    fake_firewalls = flexmock(name='fake_firewalls')
    fake_firewalls.should_receive('get').with_args(project=project_id,
      firewall='bazgroup').and_return(fake_firewall_request)
    fake_gce.should_receive('firewalls').and_return(fake_firewalls)

    # presume that we can create the network fine
    create_network = u'operation-1369175117235-4dd41ec7d6c11-8013657f'
    network_info = {
      u'status': u'PENDING',
      u'kind': u'compute#operation',
      u'name': create_network,
      u'startTime': u'2013-05-21T15:25:17.308-07:00',
      u'insertTime': u'2013-05-21T15:25:17.235-07:00',
      u'targetLink': unicode(GCEAgent.GCE_URL) + \
        u'appscale.com:appscale/global/networks/bazgroup',
      u'operationType': u'insert',
      u'progress': 0,
      u'id': u'4904874319704759670',
      u'selfLink': unicode(GCEAgent.GCE_URL) + \
        u'appscale.com:appscale/global/operations/' + \
        u'operation-1369175117235-4dd41ec7d6c11-8013657f',
      u'user': u'*****@*****.**'
    }

    fake_network_insert_request = flexmock(name='fake_network_insert_request')
    fake_network_insert_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(network_info)
    fake_networks.should_receive('insert').with_args(project=project_id,
      body=dict).and_return(fake_network_insert_request)

    created_network_info = {
      u'status': u'DONE'
    }

    fake_network_checker = flexmock(name='fake_network_checker')
    fake_network_checker.should_receive('execute').and_return(
      created_network_info)
    fake_blocker.should_receive('get').with_args(project=project_id,
      operation=create_network).and_return(fake_network_checker)
    fake_gce.should_receive('globalOperations').and_return(fake_blocker)

    # and presume that we can create the firewall fine
    create_firewall = u'operation-1369176378310-4dd4237a84021-68e4dfa6'
    firewall_info = {
      u'status': u'PENDING',
      u'kind': u'compute#operation',
      u'name': create_firewall,
      u'startTime': u'2013-05-21T15:46:18.402-07:00',
      u'insertTime': u'2013-05-21T15:46:18.310-07:00',
      u'targetLink': unicode(GCEAgent.GCE_URL) + \
        u'appscale.com:appscale/global/firewalls/bazgroup',
      u'operationType': u'insert',
      u'progress': 0,
      u'id': u'13248349431060541723',
      u'selfLink': unicode(GCEAgent.GCE_URL) + \
        u'appscale.com:appscale/global/operations/' + \
        u'operation-1369176378310-4dd4237a84021-68e4dfa6',
      u'user': u'*****@*****.**'
    }

    fake_firewall_insert_request = flexmock(name='fake_firewall_insert_request')
    fake_firewall_insert_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(firewall_info)
    fake_firewalls.should_receive('insert').with_args(project=
      u'appscale.com:appscale', body=dict).and_return(fake_firewall_insert_request)

    created_firewall_info = {
      u'status': u'DONE'
    }

    fake_firewall_checker = flexmock(name='fake_network_checker')
    fake_firewall_checker.should_receive('execute').and_return(
      created_firewall_info)
    fake_blocker.should_receive('get').with_args(project=project_id,
      operation=create_firewall).and_return(fake_firewall_checker)

    # we only need to create one node, so set up mocks for that
    add_instance = u'operation-1369248752891-4dd5311848461-afc55a20'
    instance_id = 'appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d'
    add_instance_info = {
      u'status': u'PENDING',
      u'kind': u'compute#operation',
      u'name': add_instance,
      u'azone': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/us-central1-a',
      u'startTime': u'2013-05-22T11:52:32.939-07:00',
      u'insertTime': u'2013-05-22T11:52:32.891-07:00',
      u'targetLink': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/us-central1-a/instances/' + instance_id,
      u'operationType': u'insert',
      u'progress': 0,
      u'id': u'6663616273628949255',
      u'selfLink': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/us-central1-a/operations/operation-1369248752891-4dd5311848461-afc55a20',
      u'user': u'*****@*****.**'
    }

    fake_add_instance_request = flexmock(name='fake_add_instance_request')
    fake_add_instance_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return(add_instance_info)

    fake_instances = flexmock(name='fake_instances')
    fake_gce.should_receive('instances').and_return(fake_instances)
    fake_instances.should_receive('insert').with_args(project=project_id,
      body=dict, zone=str).and_return(fake_add_instance_request)

    created_instance_info = {
      u'status': u'DONE'
    }

    fake_instance_checker = flexmock(name='fake_network_checker')
    fake_instance_checker.should_receive('execute').and_return(
      created_instance_info)
    fake_blocker.should_receive('get').with_args(project=project_id,
      operation=add_instance).and_return(fake_instance_checker)

    # add some fake data in where no instances are initially running, then one
    # is (in response to our insert request)
    no_instance_info = {
    }

    list_instance_info = {
      u'items': [{
        u'status': u'RUNNING',
        u'kind': u'compute#instance',
        u'machineType': u'https://www.googleapis.com/compute/v1/projects/appscale.com:appscale/zones/us-central1-a/machineTypes/' + instance_type,
        u'name': instance_id,
        u'zone': u'https://www.googleapis.com/compute/v1/projects/appscale.com:appscale/zones/us-central1-a',
        u'tags': {u'fingerprint': u'42WmSpB8rSM='},
        u'image': u'https://www.googleapis.com/compute/v1/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/v1/projects/appscale.com:appscale/zones/us-central1-a/instances/' + instance_id,
        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/v1/projects/appscale.com:appscale/global/networks/bazgroup',
          u'name': u'nic0'
        }]
      }],
      u'kind': u'compute#instanceList',
      u'id': u'projects/appscale.com:appscale/zones/us-central1-a/instances',
      u'selfLink': u'https://www.googleapis.com/compute/v1/projects/961228229472/zones/us-central1-a/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(no_instance_info).and_return(
        no_instance_info).and_return(list_instance_info)

    fake_instances.should_receive('list').with_args(project=project_id,
      filter="name eq appscale-bazgroup-.*", zone=zone) \
      .and_return(fake_list_instance_request)

    fake_instances.should_receive('list').with_args(project=project_id,
      zone=zone).and_return(fake_list_instance_request)

    # mock out deleting the public IP from the instance
    fake_delete_access_request = flexmock(name='fake_delete_access_request')
    fake_delete_access_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return()

    fake_instances.should_receive('deleteAccessConfig').with_args(
      project=project_id, accessConfig=str, instance=instance_id,
      networkInterface=str, zone=zone).and_return(fake_delete_access_request)

    # as well as adding in the new, static IP to the instance
    fake_add_access_request = flexmock(name='fake_add_access_request')
    fake_add_access_request.should_receive('execute').with_args(
      http=fake_authorized_http).and_return()

    fake_instances.should_receive('addAccessConfig').with_args(
      project=project_id, instance=instance_id, networkInterface=str,
      zone=zone, body=dict).and_return(fake_add_access_request)

    # finally, inject our fake GCE connection
    flexmock(apiclient.discovery)
    apiclient.discovery.should_receive('build').with_args('compute', str) \
      .and_return(fake_gce)

    # assume that root login is not enabled
    self.local_state.should_receive('shell').with_args(re.compile('ssh'),
      False, 5, stdin='ls').and_raise(ShellException)

    # assume that we can enable root login
    self.local_state.should_receive('shell').with_args(re.compile('ssh'),
      False, 5, stdin=re.compile('sudo cp')).and_return()

    # and assume that we can copy over our ssh keys fine
    self.local_state.should_receive('shell').with_args(re.compile('scp .*[r|d]sa'),
      False, 5).and_return()
    self.local_state.should_receive('shell').with_args(re.compile('scp .*{0}'
      .format(self.keyname)), False, 5).and_return()

    self.setup_appscale_compatibility_mocks()

    # mock out generating the private key
    self.local_state.should_receive('shell').with_args(re.compile('openssl'),
      False, stdin=None)

    # assume that we started monit fine
    self.local_state.should_receive('shell').with_args(re.compile('ssh'),
      False, 5, stdin=re.compile('monit'))

    # and that we copied over the AppController's monit file
    self.local_state.should_receive('shell').with_args(re.compile('scp'),
      False, 5, stdin=re.compile('controller-17443.cfg'))

    self.setup_socket_mocks('static-ip')
    self.setup_appcontroller_mocks('static-ip', 'private1')

    # mock out reading the locations.json file, and slip in our own json
    self.local_state.should_receive('get_local_nodes_info').and_return(json.loads(
      json.dumps([{
        "public_ip" : "static-ip",
        "private_ip" : "private1",
        "jobs" : ["shadow", "login"]
      }])))

    # copying over the locations yaml and json files should be fine
    self.local_state.should_receive('shell').with_args(re.compile('scp'),
      False, 5, stdin=re.compile('locations-{0}'.format(self.keyname)))

    # same for the secret key
    self.local_state.should_receive('shell').with_args(re.compile('scp'),
      False, 5, stdin=re.compile('{0}.secret'.format(self.keyname)))

    self.setup_uaserver_mocks('static-ip')

    # Finally, pretend we're using a single persistent disk.
    disk_layout = yaml.safe_load("""
node-1: my-persistent-disk-1
    """)

    argv = [
      "--min", "1",
      "--max", "1",
      "--disks", base64.b64encode(yaml.dump(disk_layout)),
      "--group", self.group,
      "--infrastructure", "gce",
      "--gce_instance_type", instance_type,
      "--machine", image_name,
      "--keyname", self.keyname,
      "--client_secrets", client_secrets,
      "--project", project_id,
      "--test",
      "--zone", "my-zone1-b",
      "--static_ip", "static-ip"
    ]

    options = ParseArgs(argv, self.function).args
    AppScaleTools.run_instances(options)
    def test_terminate_in_gce_and_succeeds(self):
        # let's say that there is a locations.yaml file, 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_locations_yaml_location(
                self.keyname)).and_return(True)
        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.yaml file, and pretend that we're on
        # GCE
        project_id = "1234567890"
        zone = 'my-zone-1b'
        builtins = flexmock(sys.modules['__builtin__'])
        builtins.should_call('open')

        fake_yaml_file = flexmock(name='fake_file')
        fake_yaml_file.should_receive('read').and_return(
            yaml.dump({
                'infrastructure': 'gce',
                'group': self.group,
                'project': project_id,
                'zone': zone
            }))
        builtins.should_receive('open').with_args(
          LocalState.get_locations_yaml_location(self.keyname), 'r') \
          .and_return(fake_yaml_file)

        # mock out reading the json file, and pretend that we're running in a
        # two node deployment
        fake_json_file = flexmock(name='fake_file')
        fake_json_file.should_receive('read').and_return(
            json.dumps([{
                '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'appscale-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/appscale-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'appscale-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/appscale-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 appscale-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/appscale-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/appscale-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='appscale-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='appscale-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)

        # 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_yaml_location(self.keyname)).and_return()
        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()

        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)
예제 #8
0
  def test_gce_run_instances(self):
    # mock out interactions with 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(
      GCEAgent.CLIENT_SECRETS_LOCATION, scope=GCEAgent.GCE_SCOPE).and_return(
      fake_flow)

    fake_storage = flexmock(name='fake_storage')
    fake_storage.should_receive('get').and_return(None)

    flexmock(oauth2client.file)
    oauth2client.file.should_receive('Storage').with_args(
      GCEAgent.OAUTH2_STORAGE_LOCATION).and_return(fake_storage)

    fake_credentials = flexmock(name='fake_credentials')
    flexmock(oauth2client.tools)
    oauth2client.tools.should_receive('run').with_args(fake_flow,
      fake_storage).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)

    # add some fake data in where no instances are initially running, then one
    # is (in response to our insert request)
    no_instance_info = {
    }

    instance_id = u'appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d'
    list_instance_info = {
      u'items': [{
        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': instance_id,
        u'zone': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/zones/us-central1-a',
        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/us-central1-a/instances/appscale-bazgroup-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'public-ip'
          }],
          u'networkIP': u'private-ip',
          u'network': u'https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazgroup',
          u'name': u'nic0'
        }]
      }],
      u'kind': u'compute#instanceList',
      u'id': u'projects/appscale.com:appscale/zones/us-central1-a/instances',
      u'selfLink': u'https://www.googleapis.com/compute/v1beta14/projects/961228229472/zones/us-central1-a/instances'
    }

    fake_list_instance_request = flexmock(name='fake_list_instance_request')
    fake_list_instance_request.should_receive('execute').with_args(
      fake_authorized_http).and_return(no_instance_info).and_return(
        list_instance_info)

    fake_instances = flexmock(name='fake_instances')
    fake_gce = flexmock(name='fake_gce')
    fake_gce.should_receive('instances').and_return(fake_instances)
    fake_instances.should_receive('list').with_args(project=self.project,
      filter="name eq appscale-boogroup-.*", zone=GCEAgent.DEFAULT_ZONE) \
      .and_return(fake_list_instance_request)

    # we only need to create one node, so set up mocks for that
    add_instance = u'operation-1369248752891-4dd5311848461-afc55a20'
    add_instance_info = {
      u'status': u'PENDING',
      u'kind': u'compute#operation',
      u'name': add_instance,
      u'azone': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/us-central1-a',
      u'startTime': u'2013-05-22T11:52:32.939-07:00',
      u'insertTime': u'2013-05-22T11:52:32.891-07:00',
      u'targetLink': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/us-central1-a/instances/appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d',
      u'operationType': u'insert',
      u'progress': 0,
      u'id': u'6663616273628949255',
      u'selfLink': unicode(GCEAgent.GCE_URL) + u'appscale.com:appscale/zones/us-central1-a/operations/operation-1369248752891-4dd5311848461-afc55a20',
      u'user': u'*****@*****.**'
    }

    fake_add_instance_request = flexmock(name='fake_add_instance_request')
    fake_add_instance_request.should_receive('execute').with_args(
      fake_authorized_http).and_return(add_instance_info)

    fake_instances.should_receive('insert').with_args(project=self.project,
      body=dict, zone=str).and_return(fake_add_instance_request)

    created_instance_info = {
      u'status': u'DONE'
    }

    fake_instance_checker = flexmock(name='fake_network_checker')
    fake_instance_checker.should_receive('execute').and_return(
      created_instance_info)

    fake_blocker = flexmock(name='fake_blocker')
    fake_gce.should_receive('globalOperations').and_return(fake_blocker)
    fake_blocker.should_receive('get').with_args(project=self.project,
      operation=add_instance).and_return(fake_instance_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)

    i = InfrastructureManager(blocking=True)

    # first, validate that the run_instances call goes through successfully
    # and gives the user a reservation id
    full_params = {
      'credentials' : {
        'EC2_URL': None,
        'EC2_ACCESS_KEY': None,
        'EC2_SECRET_KEY': None,
      },
      'project': self.project,
      'group': 'boogroup',
      'image_id': 'booid',
      'infrastructure': 'gce',
      'instance_type': 'booinstance_type',
      'keyname': 'bookeyname',
      'num_vms': '1',
      'use_spot_instances': False,
    }

    full_result = {
      'success': True,
      'reservation_id': self.reservation_id,
      'reason': 'none'
    }
    self.assertEquals(full_result, i.run_instances(full_params, 'secret'))

    # next, look at run_instances internally to make sure it actually is
    # updating its reservation info
    self.assertEquals(InfrastructureManager.STATE_RUNNING, i.reservations.get(
      self.reservation_id)['state'])
    vm_info = i.reservations.get(self.reservation_id)['vm_info']
    self.assertEquals(['public-ip'], vm_info['public_ips'])
    self.assertEquals(['private-ip'], vm_info['private_ips'])
    self.assertEquals([instance_id], vm_info['instance_ids'])
    def test_terminate_in_gce_and_succeeds(self):
        # let's say that there is a locations.yaml file, 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_secret_key_location(self.keyname)).and_return(True)
        os.path.should_receive("exists").with_args(LocalState.get_locations_yaml_location(self.keyname)).and_return(
            True
        )
        os.path.should_receive("exists").with_args(LocalState.get_client_secrets_location(self.keyname)).and_return(
            True
        )

        # mock out reading the locations.yaml file, and pretend that we're on
        # GCE
        project_id = "1234567890"
        zone = "my-zone-1b"
        builtins = flexmock(sys.modules["__builtin__"])
        builtins.should_call("open")

        fake_yaml_file = flexmock(name="fake_file")
        fake_yaml_file.should_receive("read").and_return(
            yaml.dump({"infrastructure": "gce", "group": self.group, "project": project_id, "zone": zone})
        )
        builtins.should_receive("open").with_args(LocalState.get_locations_yaml_location(self.keyname), "r").and_return(
            fake_yaml_file
        )

        # mock out reading the json file, and pretend that we're running in a
        # two node deployment
        fake_json_file = flexmock(name="fake_file")
        fake_json_file.should_receive("read").and_return(
            json.dumps([{"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)

        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").with_args(fake_flow, fake_storage).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"appscale-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/appscale-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"appscale-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/appscale-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 appscale-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/appscale-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/appscale-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="appscale-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="appscale-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)

        # 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_yaml_location(self.keyname)).and_return()
        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()

        argv = ["--keyname", self.keyname, "--test"]
        options = ParseArgs(argv, self.function).args
        AppScaleTools.terminate_instances(options)
예제 #10
0
    def test_gce_run_instances(self):
        # mock out interactions with GCE
        # first, mock out the oauth library calls
        fake_credentials = flexmock(name="fake_credentials")
        fake_storage = flexmock(name="fake_storage")
        fake_storage.should_receive("get").and_return(fake_credentials)

        flexmock(oauth2client.file)
        oauth2client.file.should_receive("Storage").with_args(GCEAgent.OAUTH2_STORAGE_LOCATION).and_return(fake_storage)

        # 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)

        # add some fake data in where no instances are initially running, then one
        # is (in response to our insert request)
        no_instance_info = {}

        instance_id = u"appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d"
        list_instance_info = {
            u"items": [
                {
                    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": instance_id,
                    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/appscale-bazgroup-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"public-ip",
                                }
                            ],
                            u"networkIP": u"private-ip",
                            u"network": u"https://www.googleapis.com/compute/v1beta14/projects/appscale.com:appscale/global/networks/bazgroup",
                            u"name": u"nic0",
                        }
                    ],
                }
            ],
            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(fake_authorized_http).and_return(
            no_instance_info
        ).and_return(list_instance_info)

        fake_instances = flexmock(name="fake_instances")
        fake_gce = flexmock(name="fake_gce")
        fake_gce.should_receive("instances").and_return(fake_instances)
        fake_instances.should_receive("list").with_args(
            project=self.project, filter="name eq appscale-boogroup-.*", zone="my-zone-1b"
        ).and_return(fake_list_instance_request)

        # we only need to create one node, so set up mocks for that
        add_instance = u"operation-1369248752891-4dd5311848461-afc55a20"
        add_instance_info = {
            u"status": u"PENDING",
            u"kind": u"compute#operation",
            u"name": add_instance,
            u"azone": unicode(GCEAgent.GCE_URL) + u"appscale.com:appscale/zones/my-zone-1b",
            u"startTime": u"2013-05-22T11:52:32.939-07:00",
            u"insertTime": u"2013-05-22T11:52:32.891-07:00",
            u"targetLink": unicode(GCEAgent.GCE_URL)
            + u"appscale.com:appscale/zones/my-zone-1b/instances/appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d",
            u"operationType": u"insert",
            u"progress": 0,
            u"id": u"6663616273628949255",
            u"selfLink": unicode(GCEAgent.GCE_URL)
            + u"appscale.com:appscale/zones/my-zone-1b/operations/operation-1369248752891-4dd5311848461-afc55a20",
            u"user": u"*****@*****.**",
        }

        fake_add_instance_request = flexmock(name="fake_add_instance_request")
        fake_add_instance_request.should_receive("execute").with_args(fake_authorized_http).and_return(
            add_instance_info
        )

        fake_instances.should_receive("insert").with_args(project=self.project, body=dict, zone=str).and_return(
            fake_add_instance_request
        )

        created_instance_info = {u"status": u"DONE"}

        fake_instance_checker = flexmock(name="fake_network_checker")
        fake_instance_checker.should_receive("execute").and_return(created_instance_info)

        fake_blocker = flexmock(name="fake_blocker")
        fake_gce.should_receive("globalOperations").and_return(fake_blocker)
        fake_blocker.should_receive("get").with_args(project=self.project, operation=add_instance).and_return(
            fake_instance_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)

        i = InfrastructureManager(blocking=True)

        # first, validate that the run_instances call goes through successfully
        # and gives the user a reservation id
        full_result = {"success": True, "reservation_id": self.reservation_id, "reason": "none"}
        self.assertEquals(full_result, i.run_instances(self.params, "secret"))

        # next, look at run_instances internally to make sure it actually is
        # updating its reservation info
        self.assertEquals(InfrastructureManager.STATE_RUNNING, i.reservations.get(self.reservation_id)["state"])
        vm_info = i.reservations.get(self.reservation_id)["vm_info"]
        self.assertEquals(["public-ip"], vm_info["public_ips"])
        self.assertEquals(["private-ip"], vm_info["private_ips"])
        self.assertEquals([instance_id], vm_info["instance_ids"])
    def test_appscale_in_one_node_gce_deployment(self):
        # presume that our client_secrets file exists
        project_id = "1234567890"
        client_secrets = "/boo/client_secrets.json"
        instance_type = "n1-standard-8"
        zone = "my-zone-1b"
        os.path.should_receive("exists").with_args(client_secrets).and_return(True)

        # and that the user does not have an ssh key set up, forcing us to create
        # one for them
        private_key = "{0}{1}.key".format(LocalState.LOCAL_APPSCALE_PATH, self.keyname)
        public_key = "{0}{1}.pub".format(LocalState.LOCAL_APPSCALE_PATH, self.keyname)

        os.path.should_receive("exists").with_args(private_key).and_return(False)
        os.path.should_receive("exists").with_args(public_key).and_return(False)

        self.local_state.should_receive("shell").with_args(re.compile("^ssh-keygen"), False).and_return()

        flexmock(os)
        original_private_key = LocalState.LOCAL_APPSCALE_PATH + self.keyname
        os.should_receive("chmod").with_args(original_private_key, 0600)
        os.should_receive("chmod").with_args(public_key, 0600)

        flexmock(shutil)
        shutil.should_receive("copy").with_args(original_private_key, private_key)

        # also, we should be able to copy over our secret.json file fine
        shutil.should_receive("copy").with_args(client_secrets, LocalState.get_client_secrets_location(self.keyname))

        # let's say that appscale isn't already running
        self.local_state.should_receive("ensure_appscale_isnt_running").and_return()
        self.local_state.should_receive("make_appscale_directory").and_return()

        # mock out talking to logs.appscale.com
        fake_connection = flexmock(name="fake_connection")
        fake_connection.should_receive("request").with_args("POST", "/upload", str, AppScaleLogger.HEADERS).and_return()

        flexmock(httplib)
        httplib.should_receive("HTTPConnection").with_args("logs.appscale.com").and_return(fake_connection)

        # mock out generating the secret key
        flexmock(uuid)
        uuid.should_receive("uuid4").and_return("the secret")

        # mock out writing the secret key to ~/.appscale, as well as reading it
        # later
        secret_key_location = LocalState.get_secret_key_location(self.keyname)
        fake_secret = flexmock(name="fake_secret")
        fake_secret.should_receive("read").and_return("the secret")
        fake_secret.should_receive("write").and_return()
        self.builtins.should_receive("open").with_args(secret_key_location, "r").and_return(fake_secret)
        self.builtins.should_receive("open").with_args(secret_key_location, "w").and_return(fake_secret)

        # mock out interactions with 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)

        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").with_args(fake_flow, fake_storage).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)

        # presume that there is an ssh key stored, but it isn't ours
        metadata_info = {
            u"kind": u"compute#project",
            u"description": u"",
            u"commonInstanceMetadata": {
                u"items": [{u"value": u"cgb:ssh-rsa keyinfo myhost", u"key": u"sshKeys"}],
                u"kind": u"compute#metadata",
            },
        }
        fake_metadata_request = flexmock(name="fake_metadata_request")
        fake_metadata_request.should_receive("execute").with_args(fake_authorized_http).and_return(metadata_info)

        fake_projects = flexmock(name="fake_projects")
        fake_projects.should_receive("get").with_args(project=project_id).and_return(fake_metadata_request)

        fake_gce = flexmock(name="fake_gce")
        fake_gce.should_receive("projects").and_return(fake_projects)

        # thus we will need to set the metadata with our ssh key
        fake_ssh_pub_key = flexmock(name="fake_ssh_pub_key")
        fake_ssh_pub_key.should_receive("read").and_return("ssh-rsa key2info myhost")
        self.builtins.should_receive("open").with_args(public_key).and_return(fake_ssh_pub_key)

        new_metadata_body = {
            "items": [{"value": u"cgb:ssh-rsa key2info myhost\ncgb:ssh-rsa keyinfo myhost", "key": "sshKeys"}],
            "kind": "compute#metadata",
        }

        set_metadata_name = u"operation-222222-4dd41ec7d6c11-8013657f"
        set_metadata = {
            u"status": u"PENDING",
            u"kind": u"compute#operation",
            u"name": set_metadata_name,
            u"operationType": u"insert",
            u"progress": 0,
            u"selfLink": unicode(GCEAgent.GCE_URL)
            + u"appscale.com:appscale/global/operations/"
            + u"operation-1369175117235-4dd41ec7d6c11-8013657f",
            u"user": u"*****@*****.**",
        }

        fake_set_metadata_request = flexmock(name="fake_set_metadata_request")
        fake_set_metadata_request.should_receive("execute").and_return(set_metadata)

        fake_projects.should_receive("setCommonInstanceMetadata").with_args(project=project_id, body=dict).and_return(
            fake_set_metadata_request
        )

        updated_metadata_info = {u"status": u"DONE"}

        fake_metadata_checker = flexmock(name="fake_network_checker")
        fake_metadata_checker.should_receive("execute").and_return(updated_metadata_info)
        fake_blocker = flexmock(name="fake_blocker")
        fake_blocker.should_receive("get").with_args(project=project_id, operation=set_metadata_name).and_return(
            fake_metadata_checker
        )

        # presume that our image does exist in GCE, with some fake data
        # acquired by running a not mocked version of this code
        image_name = "appscale-image-name"
        image_info = {
            u"kind": u"compute#image",
            u"description": u"",
            u"rawDisk": {u"containerType": u"TAR", u"source": u""},
            u"preferredKernel": unicode(GCEAgent.GCE_URL) + u"/google/global/kernels/gce-v20130515",
            u"sourceType": u"RAW",
            u"creationTimestamp": u"2013-05-21T08:05:12.198-07:00",
            u"id": u"4235320207849085220",
            u"selfLink": unicode(GCEAgent.GCE_URL) + u"961228229472/global/images/" + unicode(image_name),
            u"name": unicode(image_name),
        }
        fake_image_request = flexmock(name="fake_image_request")
        fake_image_request.should_receive("execute").with_args(fake_authorized_http).and_return(image_info)

        fake_images = flexmock(name="fake_images")
        fake_images.should_receive("get").with_args(project=project_id, image=image_name).and_return(fake_image_request)

        fake_gce.should_receive("images").and_return(fake_images)

        # next, presume that the zone we want to use exists
        zone_name = "my-zone-1b"
        zone_info = {}
        fake_zone_request = flexmock(name="fake_zone_request")
        fake_zone_request.should_receive("execute").with_args(fake_authorized_http).and_return(zone_info)

        fake_zones = flexmock(name="fake_zones")
        fake_zones.should_receive("get").with_args(project=project_id, zone=zone_name).and_return(fake_zone_request)

        fake_gce.should_receive("zones").and_return(fake_zones)

        # next, presume that the persistent disk we want to use exists
        disk_name = "my-persistent-disk-1"
        disk_info = {}
        fake_disk_request = flexmock(name="fake_disk_request")
        fake_disk_request.should_receive("execute").with_args(fake_authorized_http).and_return(disk_info)

        fake_disks = flexmock(name="fake_disks")
        fake_disks.should_receive("get").with_args(project=project_id, disk=disk_name, zone=zone).and_return(
            fake_disk_request
        )

        fake_gce.should_receive("disks").and_return(fake_disks)

        # next, presume that the network doesn't exist yet
        fake_network_request = flexmock(name="fake_network_request")
        fake_network_request.should_receive("execute").with_args(fake_authorized_http).and_raise(
            apiclient.errors.HttpError, None, None
        )

        fake_networks = flexmock(name="fake_networks")
        fake_networks.should_receive("get").with_args(project=project_id, network="bazgroup").and_return(
            fake_network_request
        )
        fake_gce.should_receive("networks").and_return(fake_networks)

        # next, presume that the firewall doesn't exist yet
        fake_firewall_request = flexmock(name="fake_firewall_request")
        fake_firewall_request.should_receive("execute").with_args(fake_authorized_http).and_raise(
            apiclient.errors.HttpError, None, None
        )

        fake_firewalls = flexmock(name="fake_firewalls")
        fake_firewalls.should_receive("get").with_args(project=project_id, firewall="bazgroup").and_return(
            fake_firewall_request
        )
        fake_gce.should_receive("firewalls").and_return(fake_firewalls)

        # presume that we can create the network fine
        create_network = u"operation-1369175117235-4dd41ec7d6c11-8013657f"
        network_info = {
            u"status": u"PENDING",
            u"kind": u"compute#operation",
            u"name": create_network,
            u"startTime": u"2013-05-21T15:25:17.308-07:00",
            u"insertTime": u"2013-05-21T15:25:17.235-07:00",
            u"targetLink": unicode(GCEAgent.GCE_URL) + u"appscale.com:appscale/global/networks/bazgroup",
            u"operationType": u"insert",
            u"progress": 0,
            u"id": u"4904874319704759670",
            u"selfLink": unicode(GCEAgent.GCE_URL)
            + u"appscale.com:appscale/global/operations/"
            + u"operation-1369175117235-4dd41ec7d6c11-8013657f",
            u"user": u"*****@*****.**",
        }

        fake_network_insert_request = flexmock(name="fake_network_insert_request")
        fake_network_insert_request.should_receive("execute").with_args(fake_authorized_http).and_return(network_info)
        fake_networks.should_receive("insert").with_args(project=project_id, body=dict).and_return(
            fake_network_insert_request
        )

        created_network_info = {u"status": u"DONE"}

        fake_network_checker = flexmock(name="fake_network_checker")
        fake_network_checker.should_receive("execute").and_return(created_network_info)
        fake_blocker.should_receive("get").with_args(project=project_id, operation=create_network).and_return(
            fake_network_checker
        )
        fake_gce.should_receive("globalOperations").and_return(fake_blocker)

        # and presume that we can create the firewall fine
        create_firewall = u"operation-1369176378310-4dd4237a84021-68e4dfa6"
        firewall_info = {
            u"status": u"PENDING",
            u"kind": u"compute#operation",
            u"name": create_firewall,
            u"startTime": u"2013-05-21T15:46:18.402-07:00",
            u"insertTime": u"2013-05-21T15:46:18.310-07:00",
            u"targetLink": unicode(GCEAgent.GCE_URL) + u"appscale.com:appscale/global/firewalls/bazgroup",
            u"operationType": u"insert",
            u"progress": 0,
            u"id": u"13248349431060541723",
            u"selfLink": unicode(GCEAgent.GCE_URL)
            + u"appscale.com:appscale/global/operations/"
            + u"operation-1369176378310-4dd4237a84021-68e4dfa6",
            u"user": u"*****@*****.**",
        }

        fake_firewall_insert_request = flexmock(name="fake_firewall_insert_request")
        fake_firewall_insert_request.should_receive("execute").with_args(fake_authorized_http).and_return(firewall_info)
        fake_firewalls.should_receive("insert").with_args(project=project_id, body=dict).and_return(
            fake_firewall_insert_request
        )

        created_firewall_info = {u"status": u"DONE"}

        fake_firewall_checker = flexmock(name="fake_network_checker")
        fake_firewall_checker.should_receive("execute").and_return(created_firewall_info)
        fake_blocker.should_receive("get").with_args(project=project_id, operation=create_firewall).and_return(
            fake_firewall_checker
        )

        # we only need to create one node, so set up mocks for that
        add_instance = u"operation-1369248752891-4dd5311848461-afc55a20"
        add_instance_info = {
            u"status": u"PENDING",
            u"kind": u"compute#operation",
            u"name": add_instance,
            u"azone": unicode(GCEAgent.GCE_URL) + u"appscale.com:appscale/zones/us-central1-a",
            u"startTime": u"2013-05-22T11:52:32.939-07:00",
            u"insertTime": u"2013-05-22T11:52:32.891-07:00",
            u"targetLink": unicode(GCEAgent.GCE_URL)
            + u"appscale.com:appscale/zones/us-central1-a/instances/appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d",
            u"operationType": u"insert",
            u"progress": 0,
            u"id": u"6663616273628949255",
            u"selfLink": unicode(GCEAgent.GCE_URL)
            + u"appscale.com:appscale/zones/us-central1-a/operations/operation-1369248752891-4dd5311848461-afc55a20",
            u"user": u"*****@*****.**",
        }

        fake_add_instance_request = flexmock(name="fake_add_instance_request")
        fake_add_instance_request.should_receive("execute").with_args(fake_authorized_http).and_return(
            add_instance_info
        )

        fake_instances = flexmock(name="fake_instances")
        fake_gce.should_receive("instances").and_return(fake_instances)
        fake_instances.should_receive("insert").with_args(project=project_id, body=dict, zone=str).and_return(
            fake_add_instance_request
        )

        created_instance_info = {u"status": u"DONE"}

        fake_instance_checker = flexmock(name="fake_network_checker")
        fake_instance_checker.should_receive("execute").and_return(created_instance_info)
        fake_blocker.should_receive("get").with_args(project=project_id, operation=add_instance).and_return(
            fake_instance_checker
        )

        # add some fake data in where no instances are initially running, then one
        # is (in response to our insert request)
        no_instance_info = {}

        list_instance_info = {
            u"items": [
                {
                    u"status": u"RUNNING",
                    u"kind": u"compute#instance",
                    u"machineType": u"https://www.googleapis.com/compute/v1beta15/projects/appscale.com:appscale/zones/us-central1-a/machineTypes/"
                    + instance_type,
                    u"name": u"appscale-bazgroup-feb10b11-62bc-4536-ac25-9734f2267d6d",
                    u"zone": u"https://www.googleapis.com/compute/v1beta15/projects/appscale.com:appscale/zones/us-central1-a",
                    u"tags": {u"fingerprint": u"42WmSpB8rSM="},
                    u"image": u"https://www.googleapis.com/compute/v1beta15/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/v1beta15/projects/appscale.com:appscale/zones/us-central1-a/instances/appscale-bazgroup-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/v1beta15/projects/appscale.com:appscale/global/networks/bazgroup",
                            u"name": u"nic0",
                        }
                    ],
                }
            ],
            u"kind": u"compute#instanceList",
            u"id": u"projects/appscale.com:appscale/zones/us-central1-a/instances",
            u"selfLink": u"https://www.googleapis.com/compute/v1beta15/projects/961228229472/zones/us-central1-a/instances",
        }

        fake_list_instance_request = flexmock(name="fake_list_instance_request")
        fake_list_instance_request.should_receive("execute").with_args(fake_authorized_http).and_return(
            no_instance_info
        ).and_return(list_instance_info)

        fake_instances.should_receive("list").with_args(
            project=project_id, filter="name eq appscale-bazgroup-.*", zone=zone
        ).and_return(fake_list_instance_request)

        # finally, inject our fake GCE connection
        flexmock(apiclient.discovery)
        apiclient.discovery.should_receive("build").with_args("compute", str).and_return(fake_gce)

        # assume that root login is not enabled
        self.local_state.should_receive("shell").with_args(re.compile("ssh"), False, 5, stdin="ls").and_raise(
            ShellException
        )

        # assume that we can enable root login
        self.local_state.should_receive("shell").with_args(
            re.compile("ssh"), False, 5, stdin=re.compile("sudo cp")
        ).and_return()

        # and assume that we can copy over our ssh keys fine
        self.local_state.should_receive("shell").with_args(re.compile("scp .*[r|d]sa"), False, 5).and_return()
        self.local_state.should_receive("shell").with_args(
            re.compile("scp .*{0}".format(self.keyname)), False, 5
        ).and_return()

        self.setup_appscale_compatibility_mocks()

        # mock out generating the private key
        self.local_state.should_receive("shell").with_args(re.compile("openssl"), False, stdin=None)

        # assume that we started god fine
        self.local_state.should_receive("shell").with_args(re.compile("ssh"), False, 5, stdin=re.compile("nohup god"))

        # and that we copied over the AppController's god file
        self.local_state.should_receive("shell").with_args(
            re.compile("scp"), False, 5, stdin=re.compile("appcontroller.god")
        )

        # also, that we started the AppController itself
        self.local_state.should_receive("shell").with_args(re.compile("ssh"), False, 5, stdin=re.compile("god load"))

        self.setup_socket_mocks("public1")
        self.setup_appcontroller_mocks("public1", "private1")

        # mock out reading the locations.json file, and slip in our own json
        self.local_state.should_receive("get_local_nodes_info").and_return(
            json.loads(json.dumps([{"public_ip": "public1", "private_ip": "private1", "jobs": ["shadow", "login"]}]))
        )

        # copying over the locations yaml and json files should be fine
        self.local_state.should_receive("shell").with_args(
            re.compile("scp"), False, 5, stdin=re.compile("locations-{0}".format(self.keyname))
        )

        # same for the secret key
        self.local_state.should_receive("shell").with_args(
            re.compile("scp"), False, 5, stdin=re.compile("{0}.secret".format(self.keyname))
        )

        self.setup_uaserver_mocks("public1")

        # Finally, pretend we're using a single persistent disk.
        disk_layout = yaml.safe_load(
            """
node-1: my-persistent-disk-1
    """
        )

        argv = [
            "--min",
            "1",
            "--max",
            "1",
            "--disks",
            base64.b64encode(yaml.dump(disk_layout)),
            "--group",
            self.group,
            "--infrastructure",
            "gce",
            "--gce_instance_type",
            instance_type,
            "--machine",
            image_name,
            "--keyname",
            self.keyname,
            "--client_secrets",
            client_secrets,
            "--project",
            project_id,
            "--test",
            "--zone",
            "my-zone-1b",
        ]

        options = ParseArgs(argv, self.function).args
        AppScaleTools.run_instances(options)