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:')
Exemple #2
0
    def FetchChoiceResources(self,
                             attribute,
                             service,
                             flag_names,
                             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, ', or '.join(flag_names),
                                  punctuation))

        return choices
    def Run(self, args):

        ref = self.CreateReference(args)
        request_class = self.service.GetRequestType(self.method)
        request = request_class(project=self.project)
        self.ScopeRequest(ref, request)
        self.SetResourceName(ref, request)

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

        # Converting the objects genrator to a list triggers the
        # logic that actually populates the errors list.
        resources = list(objects)
        if errors:
            utils.RaiseToolException(errors,
                                     error_message='Could not fetch resource:')

        # TODO(broudy): determine how this output should look when empty.

        # GetIamPolicy always returns either an error or a valid policy.
        # If no policy has been set it returns a valid empty policy (just an etag.)
        # It is not possible to have multiple policies for one resource.
        return resources[0]
  def ComputeInstanceGroupSize(self, items):
    """Add information about Instance Group size."""
    errors = []
    items = list(items)
    zone_names = sets.Set(
        [path_simplifier.Name(result['zone']) for result in items])

    instance_groups = lister.GetZonalResources(
        service=self.compute.instanceGroups,
        project=self.project,
        requested_zones=zone_names,
        filter_expr=None,
        http=self.http,
        batch_url=self.batch_url,
        errors=errors)
    instance_group_ref_to_size = dict([
        (path_simplifier.ScopedSuffix(ig.selfLink), ig.size)
        for ig in instance_groups
    ])

    if errors:
      utils.RaiseToolException(errors)

    for item in items:
      self_link = item['selfLink']
      gm_self_link = self_link.replace(
          '/instanceGroupManagers/', '/instanceGroups/')
      scoped_suffix = path_simplifier.ScopedSuffix(gm_self_link)
      size = instance_group_ref_to_size[scoped_suffix]

      item['size'] = str(size)
      yield item
  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 = lister.ProcessResults(objects, field_selector)
    resources = list(self.ComputeDynamicProperties(args, resources))

    if errors:
      utils.RaiseToolException(
          errors,
          error_message='Could not fetch resource:')
    return resources[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
  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
  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)
Exemple #9
0
def AutoscalersForZones(zones,
                        project,
                        compute,
                        http,
                        batch_url,
                        fail_when_api_not_supported=True):
    """Finds all Autoscalers defined for a given project and zones.

  Args:
    zones: target zones
    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=zones,
                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
Exemple #10
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]
Exemple #11
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]
Exemple #12
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]
  def ComputeInstanceGroupManagerMembership(self, items,
                                            filter_mode=(
                                                InstanceGroupFilteringMode
                                                .all_groups)):
    """Add information if instance group is managed."""
    errors = []
    items = list(items)
    zone_names = sets.Set(
        [path_simplifier.Name(result['zone']) for result in items])

    instance_group_managers = lister.GetZonalResources(
        service=self.compute.instanceGroupManagers,
        project=self.project,
        requested_zones=zone_names,
        filter_expr=None,
        http=self.http,
        batch_url=self.batch_url,
        errors=errors)
    instance_group_managers_refs = sets.Set([
        path_simplifier.ScopedSuffix(igm.selfLink)
        for igm in instance_group_managers])

    if errors:
      utils.RaiseToolException(errors)

    for item in items:
      self_link = item['selfLink']
      igm_self_link = self_link.replace(
          '/instanceGroups/', '/instanceGroupManagers/')
      scoped_suffix = path_simplifier.ScopedSuffix(igm_self_link)
      is_managed = scoped_suffix in instance_group_managers_refs

      if (is_managed and
          filter_mode == InstanceGroupFilteringMode.only_unmanaged_groups):
        continue
      elif (not is_managed and
            filter_mode == InstanceGroupFilteringMode.only_managed_groups):
        continue

      item['isManaged'] = ('Yes' if is_managed else 'No')
      if is_managed:
        item['instanceGroupManagerUri'] = igm_self_link
      yield item
Exemple #14
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])
Exemple #15
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:')
  def Run(self, args, request_protobufs=None, service=None):
    if request_protobufs is None:
      request_protobufs = self.CreateRequests(args)
    if service is None:
      service = self.service
    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((service, method, proto))

    errors = []
    # We want to run through the generator that MakeRequests returns in order to
    # actually make the requests, since these requests mutate resources.
    resources = list(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))

    if errors:
      utils.RaiseToolException(errors)

    return resources
Exemple #17
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)
  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:
      try:
        file_contents = edit.OnlineEdit(file_contents)
      except edit.NoSaveException:
        raise calliope_exceptions.ToolException('Edit aborted by user.')
      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
  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)
    items = self.ComputeDynamicProperties(args, items)

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

    if errors:
      utils.RaiseToolException(errors)