Exemplo n.º 1
0
  def Run(self, args):
    self.ref = self.CreateReference(args)
    get_request = self.GetGetRequest(args)

    errors = []
    objects = list(request_helper.MakeRequests(
        requests=[get_request],
        http=self.http,
        batch_url=self.batch_url,
        errors=errors,
        custom_get_requests=None))
    if errors:
      utils.RaiseToolException(
          errors,
          error_message='There was a problem fetching the resource:')

    new_object = self.Modify(args, objects[0])

    # If existing object is equal to the proposed object or if
    # Modify() returns None, then there is no work to be done, so we
    # print the resource and return.
    if not new_object or objects[0] == new_object:
      for resource in lister.ProcessResults(
          resources=[objects[0]],
          field_selector=property_selector.PropertySelector(
              properties=None,
              transformations=self.transformations)):
        yield resource
      return

    resources = request_helper.MakeRequests(
        requests=[self.GetSetRequest(args, new_object, objects[0])],
        http=self.http,
        batch_url=self.batch_url,
        errors=errors,
        custom_get_requests=None)

    resources = lister.ProcessResults(
        resources=resources,
        field_selector=property_selector.PropertySelector(
            properties=None,
            transformations=self.transformations))
    for resource in resources:
      yield resource

    if errors:
      utils.RaiseToolException(
          errors,
          error_message='There was a problem modifying the resource:')
Exemplo n.º 2
0
    def Run(self, args):
        """Returns a list of TargetPoolInstanceHealth objects."""
        self.target_pool_ref = self.CreateRegionalReference(
            args.name, args.region, resource_type='targetPools')
        target_pool = self.GetTargetPool()
        instances = target_pool.instances

        # If the target pool has no instances, we should return an empty
        # list.
        if not instances:
            return

        requests = []
        for instance in instances:
            request_message = self.messages.ComputeTargetPoolsGetHealthRequest(
                instanceReference=self.messages.InstanceReference(
                    instance=instance),
                project=self.project,
                region=self.target_pool_ref.region,
                targetPool=self.target_pool_ref.Name())
            requests.append((self.service, 'GetHealth', request_message))

        errors = []
        resources = request_helper.MakeRequests(requests=requests,
                                                http=self.http,
                                                batch_url=self.batch_url,
                                                errors=errors,
                                                custom_get_requests=None)

        for resource in resources:
            yield resource

        if errors:
            utils.RaiseToolException(
                errors, error_message='Could not get health for some targets:')
Exemplo n.º 3
0
  def Run(self, args):
    """Yields JSON-serializable dicts of resources."""
    # The field selector should be constructed before any resources
    # are fetched, so if there are any syntactic errors with the
    # fields, we can fail fast.
    field_selector = property_selector.PropertySelector(properties=args.fields)
    ref = self.CreateReference(args)

    get_request_class = self.service.GetRequestType(self.method)

    request = get_request_class(project=self.project)
    self.SetNameField(ref, request)
    self.ScopeRequest(ref, request)

    get_request = (self.service, self.method, request)

    errors = []
    objects = request_helper.MakeRequests(
        requests=[get_request],
        http=self.http,
        batch_url=self.batch_url,
        errors=errors,
        custom_get_requests=None)

    resources = list(lister.ProcessResults(objects, field_selector))

    if errors:
      utils.RaiseToolException(
          errors,
          error_message='Could not fetch resource:')
    return resources[0]
Exemplo n.º 4
0
  def Run(self, args):
    request_protobufs = self.CreateRequests(args)
    requests = []
    # If a method is not passed as part of a tuple then use the self.method
    # default
    for request in request_protobufs:
      if isinstance(request, tuple):
        method = request[0]
        proto = request[1]
      else:
        method = self.method
        proto = request
      requests.append((self.service, method, proto))

    errors = []
    resources = request_helper.MakeRequests(
        requests=requests,
        http=self.http,
        batch_url=self.batch_url,
        errors=errors,
        custom_get_requests=self.custom_get_requests)

    resources = lister.ProcessResults(
        resources=resources,
        field_selector=property_selector.PropertySelector(
            properties=None,
            transformations=self.transformations))
    for resource in resources:
      yield resource

    if errors:
      utils.RaiseToolException(errors)
Exemplo n.º 5
0
  def Run(self, args):
    sort_key_fn = None
    descending = False
    errors = []

    if args.uri:
      field_selector = None
    else:
      field_selector = property_selector.PropertySelector(
          properties=None,
          transformations=self._FIELD_TRANSFORMS)

    sort_key_fn, descending = GetSortKey(args.sort_by, self._LIST_TABS)
    responses, errors = self.GetResources(args)
    if errors:
      utils.RaiseToolException(errors)
    items = lister.ProcessResults(
        resources=list(_UnwrapResponse(responses, self.list_field)),
        field_selector=field_selector,
        sort_key_fn=sort_key_fn,
        reverse_sort=descending,
        limit=args.limit)

    for item in items:
      if args.uri:
        yield item['instance']
      else:
        yield item
Exemplo n.º 6
0
  def Run(self, args):
    """Yields JSON-serializable dicts of resources or self links."""
    # Data structures used to perform client-side filtering of
    # resources by their names and/or URIs.
    self.self_links = set()
    self.names = set()
    self.resource_refs = []

    if args.uri:
      field_selector = None
    else:
      # The field selector should be constructed before any resources
      # are fetched, so if there are any syntactic errors with the
      # fields, we can fail fast.
      field_selector = property_selector.PropertySelector(
          properties=None,
          transformations=self.transformations)

    if args.sort_by:
      if args.sort_by.startswith('~'):
        sort_by = args.sort_by[1:]
        descending = True
      else:
        sort_by = args.sort_by
        descending = False

      for col_name, path in self._resource_spec.table_cols:
        if sort_by == col_name:
          sort_by = path
          break

      if isinstance(sort_by, property_selector.PropertyGetter):
        property_getter = sort_by
      else:
        property_getter = property_selector.PropertyGetter(sort_by)
      sort_key_fn = property_getter.Get

    else:
      sort_key_fn = None
      descending = False

    errors = []

    self.PopulateResourceFilteringStructures(args)
    items = self.FilterResults(args, self.GetResources(args, errors))
    items = lister.ProcessResults(
        resources=items,
        field_selector=field_selector,
        sort_key_fn=sort_key_fn,
        reverse_sort=descending,
        limit=args.limit)

    for item in items:
      if args.uri:
        yield item['selfLink']
      else:
        yield item

    if errors:
      utils.RaiseToolException(errors)
Exemplo n.º 7
0
  def Run(self, args):
    """Returns a list of backendServiceGroupHealth objects."""
    self.backend_service_ref = self.CreateGlobalReference(
        args.name, resource_type='backendServices')
    backend_service = self.GetBackendService(args)
    if not backend_service.backends:
      return

    # Call GetHealth for each group in the backend service
    requests = []
    for backend in backend_service.backends:
      request_message = self.messages.ComputeBackendServicesGetHealthRequest(
          resourceGroupReference=self.messages.ResourceGroupReference(
              group=backend.group),
          project=self.project,
          backendService=self.backend_service_ref.Name())
      requests.append((self.service, 'GetHealth', request_message))

    errors = []
    resources = request_helper.MakeRequests(
        requests=requests,
        http=self.http,
        batch_url=self.batch_url,
        errors=errors,
        custom_get_requests=None)

    for resource in resources:
      yield resource

    if errors:
      utils.RaiseToolException(
          errors,
          error_message='Could not get health for some groups:')
Exemplo n.º 8
0
    def FetchChoiceResources(self,
                             attribute,
                             service,
                             flag_name,
                             prefix_filter=None):
        """Returns a list of choices used to prompt with."""
        if prefix_filter:
            filter_expr = 'name eq {0}.*'.format(prefix_filter)
        else:
            filter_expr = None

        errors = []
        global_resources = lister.GetGlobalResources(service=service,
                                                     project=self.project,
                                                     filter_expr=filter_expr,
                                                     http=self.http,
                                                     batch_url=self.batch_url,
                                                     errors=errors)

        choices = [resource for resource in global_resources]
        if errors or not choices:
            punctuation = ':' if errors else '.'
            utils.RaiseToolException(
                errors,
                'Unable to fetch a list of {0}s. Specifying [{1}] may fix this '
                'issue{2}'.format(attribute, flag_name, punctuation))

        return choices
Exemplo n.º 9
0
  def ProcessEditedResource(self, file_contents, args):
    """Returns an updated resource that was edited by the user."""

    # It's very important that we replace the characters of comment
    # lines with spaces instead of removing the comment lines
    # entirely. JSON and YAML deserialization give error messages
    # containing line, column, and the character offset of where the
    # error occurred. If the deserialization fails; we want to make
    # sure those numbers map back to what the user actually had in
    # front of him or her otherwise the errors will not be very
    # useful.
    non_comment_lines = '\n'.join(
        ' ' * len(line) if line.startswith('#') else line
        for line in file_contents.splitlines())

    modified_record = _DeserializeValue(non_comment_lines,
                                        args.format or BaseEdit.DEFAULT_FORMAT)

    # Normalizes all of the fields that refer to other
    # resource. (i.e., translates short names to URIs)
    reference_normalizer = property_selector.PropertySelector(
        transformations=self.reference_normalizers)
    modified_record = reference_normalizer.Apply(modified_record)

    if self.modifiable_record == modified_record:
      new_object = None

    else:
      modified_record['name'] = self.original_record['name']
      fingerprint = self.original_record.get('fingerprint')
      if fingerprint:
        modified_record['fingerprint'] = fingerprint

      new_object = encoding.DictToMessage(
          modified_record, self._resource_spec.message_class)

    # If existing object is equal to the proposed object or if
    # there is no new object, then there is no work to be done, so we
    # return the original object.
    if not new_object or self.original_object == new_object:
      return [self.original_object]

    errors = []
    resources = list(request_helper.MakeRequests(
        requests=[self.GetSetRequest(args, new_object, self.original_object)],
        http=self.http,
        batch_url=self.batch_url,
        errors=errors,
        custom_get_requests=None))
    if errors:
      utils.RaiseToolException(
          errors,
          error_message='Could not update resource:')

    return resources
Exemplo n.º 10
0
    def Run(self, args):
        field_selector = property_selector.PropertySelector(properties=None,
                                                            transformations=[])

        sort_key_fn, descending = GetSortKey(args.sort_by, self._COLUMNS)
        responses, errors = self._GetResources(args)
        if errors:
            utils.RaiseToolException(errors)
        return lister.ProcessResults(resources=list(
            _UnwrapResponse(responses, 'namedPorts')),
                                     field_selector=field_selector,
                                     sort_key_fn=sort_key_fn,
                                     reverse_sort=descending,
                                     limit=args.limit)
Exemplo n.º 11
0
def AutoscalersForZone(zone,
                       project,
                       compute,
                       http,
                       batch_url,
                       fail_when_api_not_supported=True):
    """Finds all Autoscalers defined for a given project and zone.

  Args:
    zone: target zone
    project: project owning resources.
    compute: module representing compute api.
    http: communication channel.
    batch_url: batch url.
    fail_when_api_not_supported: If true, raise tool exception if API does not
        support autoscaling.
  Returns:
    A list of Autoscaler objects.
  """
    # Errors is passed through library calls and modified with
    # (ERROR_CODE, ERROR_MESSAGE) tuples.
    errors = []

    if hasattr(compute, 'autoscalers'):
        # Explicit list() is required to unwind the generator and make sure errors
        # are detected at this level.
        autoscalers = list(
            lister.GetZonalResources(
                service=compute.autoscalers,
                project=project,
                requested_zones=[zone],
                http=http,
                batch_url=batch_url,
                errors=errors,
                filter_expr=None,
            ))
    else:
        autoscalers = []
        if fail_when_api_not_supported:
            errors.append((None, 'API does not support autoscaling'))

    if errors:
        utils.RaiseToolException(
            errors,
            error_message='Could not check if the Managed Instance Group is '
            'Autoscaled.')

    return autoscalers
Exemplo n.º 12
0
 def GetImage(self, image_ref):
     """Returns the image resource corresponding to the given reference."""
     errors = []
     res = list(
         request_helper.MakeRequests(requests=[
             (self.compute.images, 'Get',
              self.messages.ComputeImagesGetRequest(
                  image=image_ref.Name(), project=image_ref.project))
         ],
                                     http=self.http,
                                     batch_url=self.batch_url,
                                     errors=errors,
                                     custom_get_requests=None))
     if errors:
         utils.RaiseToolException(
             errors, error_message='Could not fetch image resource:')
     return res[0]
Exemplo n.º 13
0
 def GetProject(self):
     """Returns the project object."""
     errors = []
     objects = list(
         request_helper.MakeRequests(requests=[
             (self.compute.projects, 'Get',
              self.messages.ComputeProjectsGetRequest(
                  project=properties.VALUES.core.project.Get(
                      required=True), ))
         ],
                                     http=self.http,
                                     batch_url=self.batch_url,
                                     errors=errors,
                                     custom_get_requests=None))
     if errors:
         utils.RaiseToolException(
             errors, error_message='Could not fetch project resource:')
     return objects[0]
Exemplo n.º 14
0
    def Run(self, args):
        start = time_utils.CurrentTimeSec()
        group_ref = self.CreateZonalReference(args.name, args.zone)
        while True:
            responses, errors = self._GetResources(group_ref)
            if errors:
                utils.RaiseToolException(errors)
            if WaitUntilStable._IsGroupStable(responses[0]):
                break
            log.out.Print(WaitUntilStable._MakeWaitText(responses[0]))
            time_utils.Sleep(WaitUntilStable._TIME_BETWEEN_POLLS_SEC)

            if args.timeout and time_utils.CurrentTimeSec(
            ) - start > args.timeout:
                raise utils.TimeoutError(
                    'Timeout while waiting for group to become '
                    'stable.')
        log.out.Print('Group is stable')
Exemplo n.º 15
0
 def GetBackendService(self, _):
     """Fetches the backend service resource."""
     errors = []
     objects = list(
         request_helper.MakeRequests(requests=[
             (self.service, 'Get',
              self.messages.ComputeBackendServicesGetRequest(
                  project=self.project,
                  backendService=self.backend_service_ref.Name()))
         ],
                                     http=self.http,
                                     batch_url=self.batch_url,
                                     errors=errors,
                                     custom_get_requests=None))
     if errors:
         utils.RaiseToolException(
             errors, error_message='Could not fetch backend service:')
     return objects[0]
 def _GetSerialPortOutput(self, port=4):
     """Returns the serial port output for self.instance_ref."""
     request = (self.compute.instances, 'GetSerialPortOutput',
                self.messages.ComputeInstancesGetSerialPortOutputRequest(
                    instance=self.ref.Name(),
                    project=self.project,
                    port=port,
                    zone=self.ref.zone))
     errors = []
     objects = list(
         request_helper.MakeRequests(requests=[request],
                                     http=self.http,
                                     batch_url=self.batch_url,
                                     errors=errors,
                                     custom_get_requests=None))
     if errors:
         utils.RaiseToolException(
             errors, error_message='Could not fetch serial port output:')
     return objects[0].contents
Exemplo n.º 17
0
    def GetInstanceExternalIpAddress(self, instance_ref):
        """Returns the external ip address for the given instance."""
        request = (self.compute.instances, 'Get',
                   self.messages.ComputeInstancesGetRequest(
                       instance=instance_ref.Name(),
                       project=self.project,
                       zone=instance_ref.zone))

        errors = []
        objects = list(
            request_helper.MakeRequests(requests=[request],
                                        http=self.http,
                                        batch_url=self.batch_url,
                                        errors=errors,
                                        custom_get_requests=None))
        if errors:
            utils.RaiseToolException(errors,
                                     error_message='Could not fetch instance:')
        return GetExternalIPAddress(objects[0])
Exemplo n.º 18
0
 def GetTargetPool(self):
     """Fetches the target pool resource."""
     errors = []
     objects = list(
         request_helper.MakeRequests(requests=[
             (self.service, 'Get',
              self.messages.ComputeTargetPoolsGetRequest(
                  project=self.project,
                  region=self.target_pool_ref.region,
                  targetPool=self.target_pool_ref.Name()))
         ],
                                     http=self.http,
                                     batch_url=self.batch_url,
                                     errors=errors,
                                     custom_get_requests=None))
     if errors:
         utils.RaiseToolException(
             errors, error_message='Could not fetch target pool:')
     return objects[0]
Exemplo n.º 19
0
 def GetAddress(self, address_ref):
     """Returns the address resource corresponding to the given reference."""
     errors = []
     res = list(
         request_helper.MakeRequests(requests=[
             (self.compute.addresses, 'Get',
              self.messages.ComputeAddressesGetRequest(
                  address=address_ref.Name(),
                  project=address_ref.project,
                  region=address_ref.region))
         ],
                                     http=self.http,
                                     batch_url=self.batch_url,
                                     errors=errors,
                                     custom_get_requests=None))
     if errors:
         utils.RaiseToolException(
             errors, error_message='Could not fetch address resource:')
     return res[0]
Exemplo n.º 20
0
 def FetchDiskResources(self, disk_refs):
     """Returns a list of disk resources corresponding to the disk references."""
     requests = []
     for disk_ref in disk_refs:
         requests.append(
             (self.compute.disks, 'Get',
              self.messages.ComputeDisksGetRequest(disk=disk_ref.Name(),
                                                   project=disk_ref.project,
                                                   zone=disk_ref.zone)))
     errors = []
     res = list(
         request_helper.MakeRequests(requests=requests,
                                     http=self.http,
                                     batch_url=self.batch_url,
                                     errors=errors,
                                     custom_get_requests=None))
     if errors:
         utils.RaiseToolException(
             errors, error_message='Could not fetch some boot disks:')
     return res
Exemplo n.º 21
0
    def GetInstances(self, refs):
        """Fetches instance objects corresponding to the given references."""
        instance_get_requests = []
        for ref in refs:
            request_protobuf = self.messages.ComputeInstancesGetRequest(
                instance=ref.Name(), zone=ref.zone, project=ref.project)
            instance_get_requests.append(
                (self.service, 'Get', request_protobuf))

        errors = []
        instances = list(
            request_helper.MakeRequests(requests=instance_get_requests,
                                        http=self.http,
                                        batch_url=self.batch_url,
                                        errors=errors,
                                        custom_get_requests=None))
        if errors:
            utils.RaiseToolException(
                errors, error_message='Failed to fetch some instances:')
        return instances
Exemplo n.º 22
0
    def Run(self, args):
        instance_ref = self.CreateZonalReference(args.name, args.zone)

        request = (self.compute.instances, 'GetSerialPortOutput',
                   self.messages.ComputeInstancesGetSerialPortOutputRequest(
                       instance=instance_ref.Name(),
                       project=self.project,
                       zone=instance_ref.zone))

        errors = []
        objects = list(
            request_helper.MakeRequests(requests=[request],
                                        http=self.http,
                                        batch_url=self.batch_url,
                                        errors=errors,
                                        custom_get_requests=None))

        if errors:
            utils.RaiseToolException(
                errors, error_message='Could not fetch serial port output:')
        return objects[0].contents
Exemplo n.º 23
0
    def SetProjectMetadata(self, new_metadata):
        """Sets the project metadata to the new metadata."""
        compute = self.compute

        errors = []
        list(
            request_helper.MakeRequests(requests=[
                (compute.projects, 'SetCommonInstanceMetadata',
                 self.messages.ComputeProjectsSetCommonInstanceMetadataRequest(
                     metadata=new_metadata,
                     project=properties.VALUES.core.project.Get(required=True),
                 ))
            ],
                                        http=self.http,
                                        batch_url=self.batch_url,
                                        errors=errors,
                                        custom_get_requests=None))
        if errors:
            utils.RaiseToolException(
                errors,
                error_message='Could not add SSH key to project metadata:')
Exemplo n.º 24
0
  def Run(self, args):
    self.ref = self.CreateReference(args)
    get_request = self.GetGetRequest(args)

    errors = []
    objects = list(request_helper.MakeRequests(
        requests=[get_request],
        http=self.http,
        batch_url=self.batch_url,
        errors=errors,
        custom_get_requests=None))
    if errors:
      utils.RaiseToolException(
          errors,
          error_message='Could not fetch resource:')

    self.original_object = objects[0]
    self.original_record = encoding.MessageToDict(self.original_object)

    # Selects only the fields that can be modified.
    field_selector = property_selector.PropertySelector(
        properties=self._resource_spec.editables)
    self.modifiable_record = field_selector.Apply(self.original_record)

    buf = cStringIO.StringIO()
    for line in _HELP.splitlines():
      buf.write('#')
      if line:
        buf.write(' ')
      buf.write(line)
      buf.write('\n')

    buf.write('\n')
    buf.write(_SerializeDict(self.modifiable_record,
                             args.format or BaseEdit.DEFAULT_FORMAT))
    buf.write('\n')

    example = _SerializeDict(
        encoding.MessageToDict(self.example_resource),
        args.format or BaseEdit.DEFAULT_FORMAT)
    _WriteResourceInCommentBlock(example, 'Example resource:', buf)

    buf.write('#\n')

    original = _SerializeDict(self.original_record,
                              args.format or BaseEdit.DEFAULT_FORMAT)
    _WriteResourceInCommentBlock(original, 'Original resource:', buf)

    file_contents = buf.getvalue()
    while True:
      file_contents = edit.OnlineEdit(file_contents)
      try:
        resources = self.ProcessEditedResource(file_contents, args)
        break
      except (ValueError, yaml.error.YAMLError,
              protorpc.messages.ValidationError,
              calliope_exceptions.ToolException) as e:
        if isinstance(e, ValueError):
          message = e.message
        else:
          message = str(e)

        if isinstance(e, calliope_exceptions.ToolException):
          problem_type = 'applying'
        else:
          problem_type = 'parsing'

        message = ('There was a problem {0} your changes: {1}'
                   .format(problem_type, message))
        if not console_io.PromptContinue(
            message=message,
            prompt_string='Would you like to edit the resource again?'):
          raise calliope_exceptions.ToolException('Edit aborted by user.')

    resources = lister.ProcessResults(
        resources=resources,
        field_selector=property_selector.PropertySelector(
            properties=None,
            transformations=self.transformations))
    for resource in resources:
      yield resource
Exemplo n.º 25
0
    def CreateRequests(self, args):
        refs = self.CreateZonalReferences(args.names, args.zone)
        utils.PromptForDeletion(
            refs,
            scope_name='zone',
            prompt_title=(
                'The following instances will be deleted. Attached '
                'disks configured to be auto-deleted will be deleted '
                'unless they are attached to any other instances. '
                'Deleting a disk is irreversible and any data on the '
                'disk will be lost.'))

        if args.delete_disks or args.keep_disks:
            instance_resources = self.GetInstances(refs)

            disks_to_warn_for = []
            set_auto_delete_requests = []

            for ref, resource in zip(refs, instance_resources):
                for disk in resource.disks:
                    # Determines whether the current disk needs to have its
                    # autoDelete parameter changed.
                    if not self.AutoDeleteMustBeChanged(args, disk):
                        continue

                    # At this point, we know that the autoDelete property of the
                    # disk must be changed. Since autoDelete is a boolean, we
                    # just negate it!
                    # Yay, computer science! :) :) :)
                    new_auto_delete = not disk.autoDelete
                    if new_auto_delete:
                        disks_to_warn_for.append(disk.source)

                    set_auto_delete_requests.append((
                        self.service, 'SetDiskAutoDelete',
                        self.messages.ComputeInstancesSetDiskAutoDeleteRequest(
                            autoDelete=new_auto_delete,
                            deviceName=disk.deviceName,
                            instance=ref.Name(),
                            project=ref.project,
                            zone=ref.zone)))

            if set_auto_delete_requests:
                self.PromptIfDisksWithoutAutoDeleteWillBeDeleted(
                    args, disks_to_warn_for)
                errors = []
                list(
                    request_helper.MakeRequests(
                        requests=set_auto_delete_requests,
                        http=self.http,
                        batch_url=self.batch_url,
                        errors=errors,
                        custom_get_requests=None))
                if errors:
                    utils.RaiseToolException(
                        errors,
                        error_message=(
                            'Some requests to change disk auto-delete '
                            'behavior failed:'))

        delete_requests = []
        for ref in refs:
            request_protobuf = self.messages.ComputeInstancesDeleteRequest(
                instance=ref.Name(), zone=ref.zone, project=ref.project)
            delete_requests.append(request_protobuf)

        return delete_requests
Exemplo n.º 26
0
  def ExpandImageFlag(self, args, return_image_resource=False):
    """Resolves the --image flag value.

    If the value of --image is one of the aliases defined in the
    constants module, both the user's project and the public image
    project for the alias are queried. Otherwise, only the user's
    project is queried. If --image is an alias and --image-project is
    provided, only the given project is queried.

    Args:
      args: The command-line flags. The flags accessed are --image and
        --image-project.
      return_image_resource: If True, always makes an API call to also
        fetch the image resource.

    Returns:
      A tuple where the first element is the self link of the image. If
        return_image_resource is False, the second element is None, otherwise
        it is the image resource.
    """
    image_ref = self.resources.Parse(
        args.image or constants.DEFAULT_IMAGE,
        collection='compute.images',
        resolve=False)

    # If an image project was specified, then assume that image refers
    # to an image in that project.
    if args.image_project:
      image_project_ref = self.resources.Parse(
          args.image_project,
          collection='compute.projects')
      image_ref.project = image_project_ref.Name()
      image_ref.Resolve()
      return (image_ref.SelfLink(),
              self.GetImage(image_ref) if return_image_resource else None)

    image_ref.Resolve()
    alias = constants.IMAGE_ALIASES.get(image_ref.Name())

    # Check for hidden aliases.
    if not alias:
      alias = constants.HIDDEN_IMAGE_ALIASES.get(image_ref.Name())

    # If the image name given is not an alias and no image project was
    # provided, then assume that the image value refers to an image in
    # the user's project.
    if not alias:
      return (image_ref.SelfLink(),
              self.GetImage(image_ref) if return_image_resource else None)

    # At this point, the image is an alias and now we have to find the
    # latest one among the public image project and the user's
    # project.

    errors = []
    images = self.GetMatchingImages(image_ref.Name(), alias, errors)

    user_image = None
    public_images = []

    for image in images:
      if image.deprecated:
        continue
      if '/projects/{0}/'.format(self.project) in image.selfLink:
        user_image = image
      else:
        public_images.append(image)

    if errors or not public_images:
      # This should happen only if there is something wrong with the
      # image project (e.g., operator error) or the global control
      # plane is down.
      utils.RaiseToolException(
          errors,
          'Failed to find image for alias [{0}] in public image project [{1}].'
          .format(image_ref.Name(), alias.project))

    def GetVersion(image):
      """Extracts the "20140718" from an image name like "debian-v20140718"."""
      parts = image.name.rsplit('v', 1)
      if len(parts) != 2:
        log.debug('Skipping image with malformed name [%s].', image.name)
        return None
      return parts[1]

    public_candidate = max(public_images, key=GetVersion)
    if user_image:
      options = [user_image, public_candidate]

      idx = console_io.PromptChoice(
          options=[image.selfLink for image in options],
          default=0,
          message=('Found two possible choices for [--image] value [{0}].'
                   .format(image_ref.Name())))

      res = options[idx]

    else:
      res = public_candidate

    log.debug('Image resolved to [%s].', res.selfLink)
    return (res.selfLink, res if return_image_resource else None)