def CreateInstanceReferences(resources, compute_client, igm_ref,
                             instance_names_or_urls):
    """Creates reference to instances in instance group (zonal or regional).

  Args:
    resources: Resources parser for the client.
    compute_client: Client for the current release track.
    igm_ref: URL to the target IGM.
    instance_names_or_urls: names or full URLs of target instances.

  Returns:
    A dict where instance names are keys, and corresponding references are
    values. Unresolved names are present in dict with value None.
  """
    _InstanceNameWithReference = collections.namedtuple(
        'InstanceNameWithReference', ['instance_name', 'instance_reference'])
    instance_references = []
    # Make sure we don't have URLs here.
    names_to_resolve = [
        path_simplifier.Name(name_or_url)
        for name_or_url in instance_names_or_urls
    ]
    if igm_ref.Collection() == 'compute.instanceGroupManagers':
        for instance_name in names_to_resolve:
            instance_ref = resources.Parse(instance_name,
                                           params={
                                               'project': igm_ref.project,
                                               'zone': igm_ref.zone,
                                           },
                                           collection='compute.instances')
            instance_references.append(
                _InstanceNameWithReference(
                    instance_name=instance_name,
                    instance_reference=instance_ref.SelfLink()))
        return instance_references
    elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
        service = compute_client.apitools_client.regionInstanceGroupManagers
        request = service.GetRequestType('ListManagedInstances')(
            instanceGroupManager=igm_ref.Name(),
            region=igm_ref.region,
            project=igm_ref.project)
        resolved_references = {}
        for instance_ref in compute_client.MakeRequests(
                requests=[(service, 'ListManagedInstances', request)]):
            resolved_references[path_simplifier.Name(
                instance_ref.instance)] = instance_ref.instance
        for instance_name in names_to_resolve:
            if instance_name in resolved_references:
                instance_references.append(
                    _InstanceNameWithReference(
                        instance_name=instance_name,
                        instance_reference=resolved_references[instance_name]))
            else:
                instance_references.append(
                    _InstanceNameWithReference(instance_name=instance_name,
                                               instance_reference=None))
        return instance_references
    else:
        raise ValueError('Unknown reference type {0}'.format(
            igm_ref.Collection()))
예제 #2
0
    def ResourceGetRequest(self):
        """"Generates apitools request message to get the resource."""

        target_link = self.operation.targetLink

        if self.project:
            request = self.resource_service.GetRequestType('Get')(
                project=self.project)
        else:
            # Gets the flexible resource ID.
            if target_link is None:
                log.status.write('{0}.\n'.format(
                    _HumanFriendlyNameForOpPastTense(
                        self.operation.operationType).capitalize()))
                return
            token_list = target_link.split('/')
            flexible_resource_id = token_list[-1]
            request = self.resource_service.GetRequestType('Get')(
                securityPolicy=flexible_resource_id)
        if self.operation.zone:
            request.zone = path_simplifier.Name(self.operation.zone)
        elif self.operation.region:
            request.region = path_simplifier.Name(self.operation.region)
        name_field = self.resource_service.GetMethodConfig(
            'Get').ordered_params[-1]

        resource_name = self.followup_override or path_simplifier.Name(
            self.operation.targetLink)

        setattr(request, name_field, resource_name)
        return request
예제 #3
0
def _LocationName(instance_group):
  """Returns a location name, could be region name or zone name."""
  if 'zone' in instance_group:
    return path_simplifier.Name(instance_group['zone'])
  elif 'region' in instance_group:
    return path_simplifier.Name(instance_group['region'])
  else:
    return None
예제 #4
0
    def _GenerateAutoscalerDeleteRequests(self, holder, project, mig_requests):
        """Generates Delete requestes for autoscalers attached to instance groups.

    Args:
      holder: ComputeApiHolder, object encapsulating compute api.
      project: str, project this request should apply to.
      mig_requests: Messages which will be sent to delete instance group
        managers.

    Returns:
      Messages, which will be sent to delete autoscalers.
    """
        mig_requests = zip(*mig_requests)[2] if mig_requests else []
        zone_migs = [(request.instanceGroupManager, 'zone',
                      managed_instance_groups_utils.CreateZoneRef(
                          holder.resources, request))
                     for request in mig_requests
                     if hasattr(request, 'zone') and request.zone is not None]
        region_migs = [
            (request.instanceGroupManager, 'region',
             managed_instance_groups_utils.CreateRegionRef(
                 holder.resources, request)) for request in mig_requests
            if hasattr(request, 'region') and request.region is not None
        ]

        zones = zip(*zone_migs)[2] if zone_migs else []
        regions = zip(*region_migs)[2] if region_migs else []

        client = holder.client.apitools_client
        messages = client.MESSAGES_MODULE
        autoscalers_to_delete = managed_instance_groups_utils.AutoscalersForMigs(
            migs=zone_migs + region_migs,
            autoscalers=managed_instance_groups_utils.AutoscalersForLocations(
                zones=zones,
                regions=regions,
                compute=client,
                http=client.http,
                batch_url=holder.client.batch_url))
        requests = []
        for autoscaler in autoscalers_to_delete:
            if autoscaler.zone:
                service = client.autoscalers
                request = messages.ComputeAutoscalersDeleteRequest(
                    zone=path_simplifier.Name(autoscaler.zone))
            else:
                service = client.regionAutoscalers
                request = messages.ComputeRegionAutoscalersDeleteRequest(
                    region=path_simplifier.Name(autoscaler.region))

            request.autoscaler = autoscaler.name
            request.project = project
            requests.append((service, 'Delete', request))
        return requests
예제 #5
0
    def _GenerateAutoscalerDeleteRequests(self, mig_requests):
        """Generates Delete requestes for autoscalers attached to instance groups.

    Args:
      mig_requests: Messages which will be sent to delete instance group
        managers.

    Returns:
      Messages, which will be sent to delete autoscalers.
    """
        mig_requests = zip(*mig_requests)[2] if mig_requests else []
        zone_migs = [(request.instanceGroupManager, 'zone', request.zone)
                     for request in mig_requests
                     if hasattr(request, 'zone') and request.zone is not None]
        region_migs = [
            (request.instanceGroupManager, 'region', request.region)
            for request in mig_requests
            if hasattr(request, 'region') and request.region is not None
        ]

        zones = sorted(set(zip(*zone_migs)[2])) if zone_migs else []
        regions = sorted(set(zip(*region_migs)[2])) if region_migs else []

        autoscalers_to_delete = managed_instance_groups_utils.AutoscalersForMigs(
            migs=zone_migs + region_migs,
            autoscalers=managed_instance_groups_utils.AutoscalersForLocations(
                zones=zones,
                regions=regions,
                project=self.project,
                compute=self.compute,
                http=self.http,
                batch_url=self.batch_url),
            project=self.project)
        requests = []
        for autoscaler in autoscalers_to_delete:
            if autoscaler.zone:
                service = self.compute.autoscalers
                request = service.GetRequestType('Delete')(
                    zone=path_simplifier.Name(autoscaler.zone))
            else:
                service = self.compute.regionAutoscalers
                request = service.GetRequestType('Delete')(
                    region=path_simplifier.Name(autoscaler.region))

            request.autoscaler = autoscaler.name
            request.project = self.project
            requests.append((service, 'Delete', request))
        return requests
 def _do_get_instance_config(self, igm_ref, instance_ref):
     """Returns instance config for given instance."""
     instance_name = path_simplifier.Name(str(instance_ref))
     filter_param = 'name eq {0}'.format(instance_name)
     if igm_ref.Collection() == 'compute.instanceGroupManagers':
         service = self._client.apitools_client.instanceGroupManagers
         request = (
             self._client.messages.
             ComputeInstanceGroupManagersListPerInstanceConfigsRequest)(
                 instanceGroupManager=igm_ref.Name(),
                 project=igm_ref.project,
                 zone=igm_ref.zone,
                 filter=filter_param,
                 maxResults=1,
             )
     elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
         service = self._client.apitools_client.regionInstanceGroupManagers
         request = (
             self._client.messages.
             ComputeRegionInstanceGroupManagersListPerInstanceConfigsRequest
         )(
             instanceGroupManager=igm_ref.Name(),
             project=igm_ref.project,
             region=igm_ref.region,
             filter=filter_param,
             maxResults=1,
         )
     else:
         raise ValueError('Unknown reference type {0}'.format(
             igm_ref.Collection()))
     per_instance_configs = service.ListPerInstanceConfigs(request).items
     if per_instance_configs:
         return per_instance_configs[0]
     else:
         return None
def CreatePerInstanceConfigMessage(holder,
                                   instance_ref,
                                   stateful_disks,
                                   stateful_metadata,
                                   disk_getter=None):
  """Create per-instance config message from the given stateful disks and metadata."""
  if not disk_getter:
    disk_getter = instance_disk_getter.InstanceDiskGetter(
        instance_ref=instance_ref, holder=holder)
  messages = holder.client.messages
  disk_overrides = []
  for stateful_disk in stateful_disks or []:
    disk_overrides.append(
        GetDiskOverride(
            messages=messages,
            stateful_disk=stateful_disk,
            disk_getter=disk_getter))
  metadata_overrides = []
  # Keeping the metadata sorted to maintain consistency across commands
  for metadata_key, metadata_value in sorted(six.iteritems(stateful_metadata)):
    metadata_overrides.append(
        messages.ManagedInstanceOverride.MetadataValueListEntry(
            key=metadata_key, value=metadata_value))
  return messages.PerInstanceConfig(
      instance=str(instance_ref),
      name=path_simplifier.Name(str(instance_ref)),
      override=messages.ManagedInstanceOverride(
          disks=disk_overrides, metadata=metadata_overrides),
      preservedState=\
          MakePreservedStateFromOverrides(
              holder.client.messages, disk_overrides, metadata_overrides))
def CreateInstanceReferences(resources, compute_client, igm_ref,
                             instance_names):
    """Creates reference to instances in instance group (zonal or regional)."""
    if igm_ref.Collection() == 'compute.instanceGroupManagers':
        instance_refs = []
        for instance in instance_names:
            instance_refs.append(
                resources.Parse(instance,
                                params={
                                    'project': igm_ref.project,
                                    'zone': igm_ref.zone,
                                },
                                collection='compute.instances'))
        return [instance_ref.SelfLink() for instance_ref in instance_refs]
    else:
        service = compute_client.apitools_client.regionInstanceGroupManagers
        request = service.GetRequestType('ListManagedInstances')(
            instanceGroupManager=igm_ref.Name(),
            region=igm_ref.region,
            project=igm_ref.project)
        results = compute_client.MakeRequests(
            requests=[(service, 'ListManagedInstances',
                       request)])[0].managedInstances
        # here we assume that instances are uniquely named within RMIG
        return [
            instance_ref.instance for instance_ref in results
            if path_simplifier.Name(instance_ref.instance) in instance_names
            or instance_ref.instance in instance_names
        ]
def CreatePerInstanceConfigMessage(holder,
                                   instance_ref,
                                   stateful_disks,
                                   stateful_metadata,
                                   disk_getter=None,
                                   set_preserved_state=True):
  """Create per-instance config message from the given stateful disks and metadata."""
  if not disk_getter:
    disk_getter = instance_disk_getter.InstanceDiskGetter(
        instance_ref=instance_ref, holder=holder)
  messages = holder.client.messages
  preserved_state_disks = []
  for stateful_disk in stateful_disks or []:
    preserved_state_disks.append(
        MakePreservedStateDiskEntry(messages, stateful_disk, disk_getter))
  preserved_state_metadata = []
  # Keeping the metadata sorted to maintain consistency across commands
  for metadata_key, metadata_value in sorted(six.iteritems(stateful_metadata)):
    preserved_state_metadata.append(
        MakePreservedStateMetadataEntry(
            messages, key=metadata_key, value=metadata_value))
  per_instance_config = messages.PerInstanceConfig(
      name=path_simplifier.Name(six.text_type(instance_ref)))
  if set_preserved_state:
    per_instance_config.preservedState = messages.PreservedState(
        disks=messages.PreservedState.DisksValue(
            additionalProperties=preserved_state_disks),
        metadata=messages.PreservedState.MetadataValue(
            additionalProperties=preserved_state_metadata))
  return per_instance_config
예제 #10
0
def _CreateAlias(instance_resource):
    """Returns the alias for the given instance."""
    parts = [
        instance_resource.name,
        path_simplifier.Name(instance_resource.zone),
        properties.VALUES.core.project.Get(required=True),
    ]
    return '.'.join(parts)
예제 #11
0
    def _OperationRequest(self, verb):
        """Generates apitools request message to poll the operation."""

        if self.project:
            request = self.operation_service.GetRequestType(verb)(
                operation=self.operation.name, project=self.project)
        else:
            # Fetches the parent ID from the operation name.
            token_list = self.operation.name.split('-')
            parent_id = 'organizations/' + token_list[1]
            request = self.operation_service.GetRequestType(verb)(
                operation=self.operation.name, parentId=parent_id)
        if self.operation.zone:
            request.zone = path_simplifier.Name(self.operation.zone)
        elif self.operation.region:
            request.region = path_simplifier.Name(self.operation.region)
        return request
예제 #12
0
def GetExternalInterface(instance_resource, no_raise=False):
    """Returns the network interface of the instance with an external IP address.

  Args:
    instance_resource: An instance resource object.
    no_raise: A boolean flag indicating whether or not to return None instead of
      raising.

  Raises:
    UnallocatedIPAddressError: If the instance_resource's external IP address
      has yet to be allocated.
    MissingExternalIPAddressError: If no external IP address is found for the
      instance_resource and no_raise is False.

  Returns:
    A network interface resource object or None if no_raise and a network
    interface with an external IP address does not exist.
  """
    if instance_resource.networkInterfaces:
        for network_interface in instance_resource.networkInterfaces:
            access_configs = network_interface.accessConfigs
            if access_configs:
                if access_configs[0].natIP:
                    return network_interface
                elif not no_raise:
                    raise UnallocatedIPAddressError(
                        'Instance [{0}] in zone [{1}] has not been allocated an external '
                        'IP address yet. Try rerunning this command later.'.
                        format(instance_resource.name,
                               path_simplifier.Name(instance_resource.zone)))

    if no_raise:
        return None

    raise MissingExternalIPAddressError(
        'Instance [{0}] in zone [{1}] does not have an external IP address, '
        'so you cannot SSH into it. To add an external IP address to the '
        'instance, use [gcloud compute instances add-access-config].'.format(
            instance_resource.name,
            path_simplifier.Name(instance_resource.zone)))
예제 #13
0
    def ResourceGetRequest(self):
        """"Generates apitool request message to get the resource."""
        project = self.project
        operation = self.operation
        resource_service = self.resource_service
        followup_override = self.followup_override

        target_link = operation.targetLink

        if project:
            request = resource_service.GetRequestType('Get')(project=project)
        else:
            # Gets the flexible resource ID.
            if target_link is None:
                log.status.write('{0}.\n'.format(
                    _HumanFriendlyNameForOpPastTense(
                        operation.operationType).capitalize()))
                return
            token_list = target_link.split('/')
            flexible_resource_id = token_list[-1]
            request = resource_service.GetRequestType('Get')(
                securityPolicy=flexible_resource_id)
        if operation.zone:
            request.zone = path_simplifier.Name(operation.zone)
        elif operation.region:
            request.region = path_simplifier.Name(operation.region)
        name_field = resource_service.GetMethodConfig('Get').ordered_params[-1]

        # If the new resource that is created's name differs from the one used
        # for polling, this will check for the new resource (such as when
        # renaming an instance).

        if followup_override:
            resource_name = followup_override
        else:
            resource_name = path_simplifier.Name(operation.targetLink)

        setattr(request, name_field, resource_name)
        return request
예제 #14
0
def GetExternalIPAddress(instance_resource, no_raise=False):
    """Returns the external IP address of the instance.

  Args:
    instance_resource: An instance resource object.
    no_raise: A boolean flag indicating whether or not to return None instead of
      raising.

  Raises:
    ToolException: If no external IP address is found for the instance_resource
      and no_raise is False.

  Returns:
    A string IP or None is no_raise is True and no ip exists.
  """
    if instance_resource.networkInterfaces:
        access_configs = instance_resource.networkInterfaces[0].accessConfigs
        if access_configs:
            ip_address = access_configs[0].natIP
            if ip_address:
                return ip_address
            elif not no_raise:
                raise exceptions.ToolException(
                    'Instance [{0}] in zone [{1}] has not been allocated an external '
                    'IP address yet. Try rerunning this command later.'.format(
                        instance_resource.name,
                        path_simplifier.Name(instance_resource.zone)))

    if no_raise:
        return None

    raise exceptions.ToolException(
        'Instance [{0}] in zone [{1}] does not have an external IP address, '
        'so you cannot SSH into it. To add an external IP address to the '
        'instance, use [gcloud compute instances add-access-config].'.format(
            instance_resource.name,
            path_simplifier.Name(instance_resource.zone)))
def AddAutoscalersToMigs(migs_iterator,
                         project,
                         compute,
                         http,
                         batch_url,
                         fail_when_api_not_supported=True):
    """Add Autoscaler to each IGM object if autoscaling is enabled for it."""
    migs = list(migs_iterator)
    zone_names = set(
        [path_simplifier.Name(mig['zone']) for mig in migs if 'zone' in mig])
    region_names = set([
        path_simplifier.Name(mig['region']) for mig in migs if 'region' in mig
    ])
    autoscalers = {}
    all_autoscalers = AutoscalersForLocations(
        zones=zone_names,
        regions=region_names,
        project=project,
        compute=compute,
        http=http,
        batch_url=batch_url,
        fail_when_api_not_supported=fail_when_api_not_supported)

    for scope_name in list(zone_names) + list(region_names):
        autoscalers[scope_name] = []

    for autoscaler in all_autoscalers:
        autoscaler_scope = None
        if autoscaler.zone is not None:
            autoscaler_scope = path_simplifier.Name(autoscaler.zone)
        if hasattr(autoscaler, 'region') and autoscaler.region is not None:
            autoscaler_scope = path_simplifier.Name(autoscaler.region)
        if autoscaler_scope is not None:
            autoscalers.setdefault(autoscaler_scope, [])
            autoscalers[autoscaler_scope].append(autoscaler)

    for mig in migs:
        scope_name = None
        scope_type = None
        if 'region' in mig:
            scope_name = path_simplifier.Name(mig['region'])
            scope_type = 'region'
        elif 'zone' in mig:
            scope_name = path_simplifier.Name(mig['zone'])
            scope_type = 'zone'

        autoscaler = None
        if scope_name and scope_type:
            autoscaler = AutoscalerForMig(mig_name=mig['name'],
                                          autoscalers=autoscalers[scope_name],
                                          project=project,
                                          scope_name=scope_name,
                                          scope_type=scope_type)
        if autoscaler:
            mig['autoscaler'] = autoscaler
        yield mig
def MakeRequestsAndGetStatusPerInstance(client, requests,
                                        instances_holder_field,
                                        errors_to_collect):
    """Make *-instances requests with feedback per instance.

  Args:
    client: Compute client.
    requests: [(service, method, request)].
    instances_holder_field: name of field inside request holding list of
      instances.
    errors_to_collect: A list for capturing errors. If any response contains an
      error, it is added to this list.

  Returns:
    A list of request statuses per instance. Requests status is a dictionary
    object, see SendInstancesRequestsAndPostProcessOutputs for details.
  """

    # Make requests and collect errors for each.
    request_results = []
    for service, method, request in requests:
        errors = []
        client.MakeRequests([(service, method, request)], errors)
        request_results.append((request, errors))
        errors_to_collect.extend(errors)

    # Determine status of instances.
    status_per_instance = []
    for request, errors in request_results:
        # Currently, any validation failure means that whole request is rejected.
        if errors:
            instance_status = 'FAIL'
        else:
            instance_status = 'SUCCESS'
        for instance in getattr(request, instances_holder_field).instances:
            status_per_instance.append({
                'selfLink':
                instance,
                'instanceName':
                path_simplifier.Name(instance),
                'status':
                instance_status
            })

    return status_per_instance
예제 #17
0
def GetInternalInterface(instance_resource):
    """Returns the a network interface of the instance.

  Args:
    instance_resource: An instance resource object.

  Raises:
    ToolException: If instance has no network interfaces.

  Returns:
    A network interface resource object.
  """
    if instance_resource.networkInterfaces:
        return instance_resource.networkInterfaces[0]
    raise exceptions.ToolException(
        'Instance [{0}] in zone [{1}] has no network interfaces.'.format(
            instance_resource.name,
            path_simplifier.Name(instance_resource.zone)))
예제 #18
0
def GetInternalIPAddress(instance_resource):
    """Returns the internal IP address of the instance.

  Args:
    instance_resource: An instance resource object.

  Raises:
    ToolException: If instance has no network interfaces.

  Returns:
    A string IP or None if no_raise is True and no ip exists.
  """
    if instance_resource.networkInterfaces:
        return instance_resource.networkInterfaces[0].networkIP
    raise exceptions.ToolException(
        'Instance [{0}] in zone [{1}] has no network interfaces.'.format(
            instance_resource.name,
            path_simplifier.Name(instance_resource.zone)))
예제 #19
0
 def CreateInstanceReferences(self, group_ref, instance_names, errors):
   if group_ref.Collection() == 'compute.instanceGroupManagers':
     instances_refs = self.CreateZonalReferences(
         instance_names, group_ref.zone, resource_type='instances')
     return [instance_ref.SelfLink() for instance_ref in instances_refs]
   else:
     service = self.compute.regionInstanceGroupManagers
     request = service.GetRequestType('ListManagedInstances')(
         instanceGroupManager=group_ref.Name(),
         region=group_ref.region,
         project=self.context['project'])
     results = list(request_helper.MakeRequests(
         requests=[(service, 'ListManagedInstances', request)],
         http=self.http,
         batch_url=self.batch_url,
         errors=errors,
         custom_get_requests=None))[0].managedInstances
     # here we assume that instances are uniquely named within RMIG
     return [instance_ref.instance for instance_ref in results
             if path_simplifier.Name(instance_ref.instance) in instance_names
             or instance_ref.instance in instance_names]
def CreateInstanceReferences(holder, igm_ref, instance_names):
    """Creates references to instances in instance group (zonal or regional)."""
    if igm_ref.Collection() == 'compute.instanceGroupManagers':
        instance_refs = []
        for instance in instance_names:
            instance_refs.append(
                holder.resources.Parse(instance,
                                       params={
                                           'project': igm_ref.project,
                                           'zone': igm_ref.zone,
                                       },
                                       collection='compute.instances'))
        return instance_refs
    elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
        messages = holder.client.messages
        request = (
            messages.
            ComputeRegionInstanceGroupManagersListManagedInstancesRequest)(
                instanceGroupManager=igm_ref.Name(),
                region=igm_ref.region,
                project=igm_ref.project)
        managed_instances = list_pager.YieldFromList(
            service=holder.client.apitools_client.regionInstanceGroupManagers,
            batch_size=500,
            request=request,
            method='ListManagedInstances',
            field='managedInstances',
        )
        instances_to_return = []
        for instance_ref in managed_instances:
            if path_simplifier.Name(
                    instance_ref.instance
            ) in instance_names or instance_ref.instance in instance_names:
                instances_to_return.append(instance_ref.instance)
        return instances_to_return
    else:
        raise ValueError('Unknown reference type {0}'.format(
            igm_ref.Collection()))
예제 #21
0
def CreateInstanceReferences(scope_prompter, compute_client, group_ref,
                             instance_names):
    """Creates reference to instances in instance group (zonal or regional)."""
    compute = compute_client.apitools_client
    if group_ref.Collection() == 'compute.instanceGroupManagers':
        instances_refs = scope_prompter.CreateZonalReferences(
            instance_names, group_ref.zone, resource_type='instances')
        return [instance_ref.SelfLink() for instance_ref in instances_refs]
    else:
        service = compute.regionInstanceGroupManagers
        request = service.GetRequestType('ListManagedInstances')(
            instanceGroupManager=group_ref.Name(),
            region=group_ref.region,
            project=group_ref.project)
        results = compute_client.MakeRequests(
            requests=[(service, 'ListManagedInstances',
                       request)])[0].managedInstances
        # here we assume that instances are uniquely named within RMIG
        return [
            instance_ref.instance for instance_ref in results
            if path_simplifier.Name(instance_ref.instance) in instance_names
            or instance_ref.instance in instance_names
        ]
 def testName(self):
     for _, path in six.iteritems(self.paths):
         name = path_simplifier.Name(path)
         self.assertEqual('my-name', name)
예제 #23
0
def ComputeInstanceGroupManagerMembership(
    compute,
    project,
    http,
    batch_url,
    items,
    filter_mode=(InstanceGroupFilteringMode.ALL_GROUPS)):
    """Add information if instance group is managed.

  Args:
    compute: GCE Compute API client,
    project: str, project name
    http: http client,
    batch_url: str, batch url
    items: list of instance group messages,
    filter_mode: InstanceGroupFilteringMode, managed/unmanaged filtering options
  Returns:
    list of instance groups with computed dynamic properties
  """
    errors = []
    items = list(items)
    zone_names = set(
        [path_simplifier.Name(ig['zone']) for ig in items if 'zone' in ig])
    region_names = set(
        [path_simplifier.Name(ig['region']) for ig in items if 'region' in ig])

    if zone_names:
        zonal_instance_group_managers = lister.GetZonalResources(
            service=compute.instanceGroupManagers,
            project=project,
            requested_zones=zone_names,
            filter_expr=None,
            http=http,
            batch_url=batch_url,
            errors=errors)
    else:
        zonal_instance_group_managers = []

    if region_names and hasattr(compute, 'regionInstanceGroups'):
        # regional instance groups are just in 'alpha' API
        regional_instance_group_managers = lister.GetRegionalResources(
            service=compute.regionInstanceGroupManagers,
            project=project,
            requested_regions=region_names,
            filter_expr=None,
            http=http,
            batch_url=batch_url,
            errors=errors)
    else:
        regional_instance_group_managers = []

    instance_group_managers = (list(zonal_instance_group_managers) +
                               list(regional_instance_group_managers))
    instance_group_managers_refs = set([
        path_simplifier.ScopedSuffix(igm.selfLink)
        for igm in instance_group_managers
    ])

    if errors:
        utils.RaiseToolException(errors)

    results = []
    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
        results.append(item)

    return results
예제 #24
0
def _TargetPoolHealthChecksToCell(target_pool):
  """Comma-joins the names of health checks of the given target pool."""
  return ','.join(path_simplifier.Name(check) for check in
                  target_pool.get('healthChecks', []))
예제 #25
0
def _TargetProxySslCertificatesToCell(target_proxy):
  """Joins the names of ssl certificates of the given HTTPS or SSL proxy."""
  return ','.join(path_simplifier.Name(cert) for cert in
                  target_proxy.get('sslCertificates', []))
예제 #26
0
def WaitForOperations(operations,
                      project,
                      operation_service,
                      resource_service,
                      http,
                      batch_url,
                      warnings,
                      errors,
                      custom_get_requests=None,
                      timeout=None):
    """Blocks until the given operations are done or until a timeout is reached.

  Args:
    operations: A list of Operation objects to poll.
    project: The project to which the resources belog.
    operation_service: The service that can be used to get operation
      objects.
    resource_service: The service of the collection being mutated by
      the operations. If the operation type is not delete, this service
      is used to fetch the mutated objects after the operations are done.
    http: An HTTP object.
    batch_url: The URL to which batch requests should be sent.
    warnings: An output parameter for capturing warnings.
    errors: An output parameter for capturing errors.
    custom_get_requests: A mapping of resource names to requests. If
      this is provided, when an operation is DONE, instead of performing
      a get on the targetLink, this function will consult custom_get_requests
      and perform the request dictated by custom_get_requests.
    timeout: The maximum amount of time, in seconds, to wait for the
      operations to reach the DONE state.

  Yields:
    The resources pointed to by the operations' targetLink fields if
    the operation type is not delete. Only resources whose
    corresponding operations reach done are yielded.
  """
    timeout = timeout or _POLLING_TIMEOUT_SEC

    operation_type = operation_service.GetResponseType('Get')

    responses = []
    start = time_util.CurrentTimeSec()
    sleep_sec = 0

    while operations:
        resource_requests = []
        operation_requests = []

        log.debug('Operations to inspect: %s', operations)
        for operation in operations:
            if operation.status == operation_type.StatusValueValuesEnum.DONE:
                # The operation has reached the DONE state, so we record any
                # problems it contains (if any) and proceed to get the target
                # resource if there were no problems and the operation is not
                # a deletion.

                _RecordProblems(operation, warnings, errors)

                # We shouldn't attempt to get the target resource if there was
                # anything wrong with the operation. Note that
                # httpErrorStatusCode is set only when the operation is not
                # successful.
                if (operation.httpErrorStatusCode
                        and operation.httpErrorStatusCode != httplib.OK):
                    continue

                # Just in case the server did not set httpErrorStatusCode but
                # the operation did fail, we check the "error" field.
                if operation.error:
                    continue

                target_link = operation.targetLink

                if custom_get_requests:
                    target_link, service, request_protobuf = (
                        custom_get_requests[operation.targetLink])
                    resource_requests.append(
                        (service, 'Get', request_protobuf))

                # We shouldn't get the target resource if the operation type
                # is delete because there will be no resource left.
                elif not _IsDeleteOp(operation.operationType):
                    request = resource_service.GetRequestType('Get')(
                        project=project)
                    if operation.zone:
                        request.zone = path_simplifier.Name(operation.zone)
                    elif operation.region:
                        request.region = path_simplifier.Name(operation.region)
                    name_field = resource_service.GetMethodConfig(
                        'Get').ordered_params[-1]
                    setattr(request, name_field,
                            path_simplifier.Name(operation.targetLink))
                    resource_requests.append(
                        (resource_service, 'Get', request))

                log.status.write('{0} [{1}].\n'.format(
                    _HumanFrieldlyNameForOpPastTense(
                        operation.operationType).capitalize(), target_link))

            else:
                # The operation has not reached the DONE state, so we add a
                # get request to poll the operation.
                request = operation_service.GetRequestType('Get')(
                    operation=operation.name, project=project)
                if operation.zone:
                    request.zone = path_simplifier.Name(operation.zone)
                elif operation.region:
                    request.region = path_simplifier.Name(operation.region)
                operation_requests.append((operation_service, 'Get', request))

        requests = resource_requests + operation_requests
        if not requests:
            break

        responses, request_errors = batch_helper.MakeRequests(
            requests=requests, http=http, batch_url=batch_url)
        errors.extend(request_errors)

        operations = []
        for response in responses:
            if isinstance(response, operation_type):
                operations.append(response)
            else:
                yield response

        # If there are no more operations, we are done.
        if not operations:
            break

        # Did we time out? If so, record the operations that timed out so
        # they can be reported to the user.
        if time_util.CurrentTimeSec() - start > timeout:
            log.debug('Timeout of %ss reached.', timeout)
            _RecordUnfinishedOperations(operations, errors)
            break

        # Sleeps before trying to poll the operations again.
        sleep_sec += 1
        # Don't re-use sleep_sec, since we want to keep the same time increment
        sleep_time = min(sleep_sec, _MAX_TIME_BETWEEN_POLLS_SEC)
        log.debug('Sleeping for %ss.', sleep_time)
        time_util.Sleep(sleep_time)
예제 #27
0
def WaitForOperations(
    operations_data, http, batch_url, warnings, errors,
    progress_tracker=None, timeout=None):
  """Blocks until the given operations are done or until a timeout is reached.

  Args:
    operations_data: A list of OperationData objects holding Operations to poll.
    http: An HTTP object.
    batch_url: The URL to which batch requests should be sent.
    warnings: An output parameter for capturing warnings.
    errors: An output parameter for capturing errors.
    progress_tracker: progress tracker to tick while waiting for operations to
                      finish.
    timeout: The maximum amount of time, in seconds, to wait for the
      operations to reach the DONE state.

  Yields:
    The resources pointed to by the operations' targetLink fields if
    the operation type is not delete. Only resources whose
    corresponding operations reach done are yielded.
  """
  timeout = timeout or _POLLING_TIMEOUT_SEC

  # Operation -> OperationData mapping will be used to reify operation_service
  # and resource_service from operation_service.Get(operation) response.
  # It is necessary because poll operation is returning only response, but we
  # also need to get operation details to know the service to poll for all
  # unfinished_operations.
  operation_details = {}
  unfinished_operations = []
  for operation in operations_data:
    operation_details[operation.operation.selfLink] = operation
    unfinished_operations.append(operation.operation)

  responses = []
  start = time_util.CurrentTimeSec()
  sleep_sec = 0

  while unfinished_operations:
    if progress_tracker:
      progress_tracker.Tick()
    resource_requests = []
    operation_requests = []

    log.debug('Operations to inspect: %s', unfinished_operations)
    for operation in unfinished_operations:
      # Reify operation
      data = operation_details[operation.selfLink]
      project = data.project
      operation_service = data.operation_service
      resource_service = data.resource_service

      operation_type = operation_service.GetResponseType('Get')

      if operation.status == operation_type.StatusValueValuesEnum.DONE:
        # The operation has reached the DONE state, so we record any
        # problems it contains (if any) and proceed to get the target
        # resource if there were no problems and the operation is not
        # a deletion.

        _RecordProblems(operation, warnings, errors)

        # We shouldn't attempt to get the target resource if there was
        # anything wrong with the operation. Note that
        # httpErrorStatusCode is set only when the operation is not
        # successful.
        if (operation.httpErrorStatusCode and
            operation.httpErrorStatusCode != 200):  # httplib.OK
          continue

        # Just in case the server did not set httpErrorStatusCode but
        # the operation did fail, we check the "error" field.
        if operation.error:
          continue

        target_link = operation.targetLink

        # We shouldn't get the target resource if the operation type
        # is delete because there will be no resource left.
        if not _IsDeleteOp(operation.operationType):
          request = resource_service.GetRequestType('Get')(project=project)
          if operation.zone:
            request.zone = path_simplifier.Name(operation.zone)
          elif operation.region:
            request.region = path_simplifier.Name(operation.region)
          name_field = resource_service.GetMethodConfig(
              'Get').ordered_params[-1]
          setattr(request, name_field,
                  path_simplifier.Name(operation.targetLink))
          resource_requests.append((resource_service, 'Get', request))

        log.status.write('{0} [{1}].\n'.format(
            _HumanFrieldlyNameForOpPastTense(
                operation.operationType).capitalize(),
            target_link))

      else:
        # The operation has not reached the DONE state, so we add a
        # get request to poll the operation.
        request = operation_service.GetRequestType('Get')(
            operation=operation.name,
            project=project)
        if operation.zone:
          request.zone = path_simplifier.Name(operation.zone)
        elif operation.region:
          request.region = path_simplifier.Name(operation.region)
        operation_requests.append((operation_service, 'Get', request))

    requests = resource_requests + operation_requests
    if not requests:
      break

    responses, request_errors = batch_helper.MakeRequests(
        requests=requests,
        http=http,
        batch_url=batch_url)
    errors.extend(request_errors)

    unfinished_operations = []
    for response in responses:
      if isinstance(response, operation_type):
        unfinished_operations.append(response)
      else:
        yield response

    # If there are no more operations, we are done.
    if not unfinished_operations:
      break

    # Did we time out? If so, record the operations that timed out so
    # they can be reported to the user.
    if time_util.CurrentTimeSec() - start > timeout:
      log.debug('Timeout of %ss reached.', timeout)
      _RecordUnfinishedOperations(unfinished_operations, errors)
      break

    # Sleeps before trying to poll the operations again.
    sleep_sec += 1
    # Don't re-use sleep_sec, since we want to keep the same time increment
    sleep_time = min(sleep_sec, _MAX_TIME_BETWEEN_POLLS_SEC)
    log.debug('Sleeping for %ss.', sleep_time)
    time_util.Sleep(sleep_time)
def MakeRequestsAndGetStatusPerInstanceFromOperation(client, requests,
                                                     instances_holder_field,
                                                     warnings_to_collect,
                                                     errors_to_collect):
    """Make *-instances requests with feedback per instance.

  Specialized version of MakeRequestsAndGetStatusPerInstance. Checks operations
  for warnings presence to evaluate statuses per instance. Gracefully validated
  requests may produce warnings on operations, indicating instances skipped.
  It would be merged with MakeRequestsAndGetStatusPerInstance after we see
  there's no issues with this implementation.

  Args:
    client: Compute client.
    requests: [(service, method, request)].
    instances_holder_field: name of field inside request holding list of
      instances.
    warnings_to_collect: A list for capturing warnings. If any completed
      operation will contain skipped instances, function will append warning
      suggesting how to find additional details on the operation, warnings
      unrelated to graceful validation will be collected as is.
    errors_to_collect: A list for capturing errors. If any response contains an
      error, it is added to this list.

  Returns:
    See MakeRequestsAndGetStatusPerInstance.
  """

    # Make requests and collect errors for each.
    request_results = []

    for service, method, request in requests:
        errors = []
        operations = client.MakeRequests([(service, method, request)],
                                         errors,
                                         log_warnings=False,
                                         no_followup=True)
        # There should be only one operation in the list.
        [operation] = operations
        request_results.append((request, operation, errors))
        errors_to_collect.extend(errors)

    # Determine status of instances.
    status_per_instance = []
    for request, operation, errors in request_results:
        # If there's any errors, we assume that operation failed for all instances.
        if errors:
            for instance in getattr(request, instances_holder_field).instances:
                status_per_instance.append({
                    'selfLink':
                    instance,
                    'instanceName':
                    path_simplifier.Name(instance),
                    'status':
                    'FAIL'
                })
        else:
            skipped_instances = ExtractSkippedInstancesAndCollectOtherWarnings(
                operation, warnings_to_collect)

            for instance in getattr(request, instances_holder_field).instances:
                # Extract public path of an instance from URI. Public path is a part of
                # instance URI, which starts with 'projects/'
                instance_path = instance[instance.find('/projects/') + 1:]
                validation_error = None
                if instance_path in skipped_instances:
                    instance_status = 'SKIPPED'
                    validation_error = skipped_instances[instance_path]
                else:
                    instance_status = 'SUCCESS'
                status_per_instance.append({
                    'selfLink':
                    instance,
                    'instanceName':
                    path_simplifier.Name(instance),
                    'status':
                    instance_status,
                    'validationError':
                    validation_error
                })
    return status_per_instance