371 lines
12 KiB
Python
371 lines
12 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2021 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""Utilities for the cloud deploy describe commands."""
|
|
|
|
|
|
from apitools.base.py import exceptions as apitools_exceptions
|
|
from googlecloudsdk.command_lib.deploy import delivery_pipeline_util
|
|
from googlecloudsdk.command_lib.deploy import rollout_util
|
|
from googlecloudsdk.command_lib.deploy import target_util
|
|
from googlecloudsdk.core import log
|
|
from googlecloudsdk.core import resources
|
|
from googlecloudsdk.core.util import times
|
|
|
|
|
|
def DescribeTarget(target_ref, pipeline_id, skip_pipeline_lookup,
|
|
list_all_pipelines):
|
|
"""Describes details specific to the individual target, delivery pipeline qualified.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target reference.
|
|
pipeline_id: str, delivery pipeline ID.
|
|
skip_pipeline_lookup: Boolean, flag indicating whether to fetch information
|
|
from the pipeline(s) containing target. If set, pipeline information will
|
|
not be fetched.
|
|
list_all_pipelines: Boolean, flag indicating whether to fetch information
|
|
from all pipelines associated with target, if set to false, it will fetch
|
|
information from the most recently updated one.
|
|
|
|
Returns:
|
|
A dictionary of <section name:output>.
|
|
|
|
"""
|
|
target_obj = target_util.GetTarget(target_ref)
|
|
output = {'Target': target_obj}
|
|
if skip_pipeline_lookup:
|
|
return output
|
|
if pipeline_id:
|
|
return DescribeTargetWithPipeline(target_obj, target_ref, pipeline_id,
|
|
output)
|
|
else:
|
|
return DescribeTargetWithNoPipeline(target_obj, target_ref,
|
|
list_all_pipelines, output)
|
|
|
|
|
|
def DescribeTargetWithPipeline(target_obj, target_ref, pipeline_id, output):
|
|
"""Describes details specific to the individual target, delivery pipeline qualified.
|
|
|
|
The output contains four sections:
|
|
|
|
target
|
|
- detail of the target to be described.
|
|
|
|
latest release
|
|
- the detail of the active release in the target.
|
|
|
|
latest rollout
|
|
- the detail of the active rollout in the target.
|
|
|
|
deployed
|
|
- timestamp of the last successful deployment.
|
|
|
|
pending approvals
|
|
- list rollouts that require approval.
|
|
Args:
|
|
target_obj: protorpc.messages.Message, target object.
|
|
target_ref: protorpc.messages.Message, target reference.
|
|
pipeline_id: str, delivery pipeline ID.
|
|
output: A dictionary of <section name:output>.
|
|
|
|
Returns:
|
|
A dictionary of <section name:output>.
|
|
|
|
"""
|
|
target_dict = target_ref.AsDict()
|
|
pipeline_ref = resources.REGISTRY.Parse(
|
|
None,
|
|
collection='clouddeploy.projects.locations.deliveryPipelines',
|
|
params={
|
|
'projectsId': target_dict['projectsId'],
|
|
'locationsId': target_dict['locationsId'],
|
|
'deliveryPipelinesId': pipeline_id
|
|
})
|
|
|
|
current_rollout = target_util.GetCurrentRollout(target_ref, pipeline_ref)
|
|
output = SetCurrentReleaseAndRollout(current_rollout, output)
|
|
if target_obj.requireApproval:
|
|
output = ListPendingApprovals(target_ref, pipeline_ref, output)
|
|
return output
|
|
|
|
|
|
def DescribeTargetWithNoPipeline(target_obj, target_ref, list_all_pipelines,
|
|
output):
|
|
"""Describes details specific to the individual target.
|
|
|
|
In addition, it will also display details about pipelines associated
|
|
with the given target.
|
|
|
|
The output contains the following sections:
|
|
|
|
target
|
|
- details of the target to be described.
|
|
|
|
associated pipelines
|
|
- details of the pipelines that use the target.
|
|
|
|
For each associated pipeline, the following will be displayed:
|
|
|
|
latest release
|
|
- details of the active release in the target.
|
|
|
|
latest rollout
|
|
- details of the active rollout in the target.
|
|
|
|
deployed
|
|
- timestamp of the last successful deployment.
|
|
|
|
pending approvals
|
|
- list the rollouts that require approval.
|
|
|
|
Args:
|
|
target_obj: protorpc.messages.Message, target object.
|
|
target_ref: protorpc.messages.Message, target reference.
|
|
list_all_pipelines: Boolean, if true, will return information about all
|
|
pipelines associated with target, otherwise, the most recently active
|
|
pipeline information will be displayed.
|
|
output: A dictionary of <section name:output>.
|
|
|
|
Returns:
|
|
A dictionary of <section name:output>.
|
|
|
|
"""
|
|
sorted_pipelines = GetTargetDeliveryPipelines(target_ref)
|
|
if not sorted_pipelines:
|
|
return output
|
|
|
|
output['Number of associated delivery pipelines'] = len(sorted_pipelines)
|
|
pipeline_refs = list(
|
|
map(delivery_pipeline_util.PipelineToPipelineRef, sorted_pipelines))
|
|
if list_all_pipelines:
|
|
output['Associated delivery pipelines'] = ListAllPipelineReleaseRollout(
|
|
target_ref, pipeline_refs)
|
|
if target_obj.requireApproval:
|
|
ListPendingApprovalsMultiplePipelines(target_ref, pipeline_refs, output)
|
|
else:
|
|
active_pipeline_ref, latest_rollout = GetMostRecentlyActivePipeline(
|
|
target_ref, pipeline_refs)
|
|
if active_pipeline_ref and latest_rollout:
|
|
output['Active Pipeline'] = SetMostRecentlyActivePipeline(
|
|
active_pipeline_ref, latest_rollout)
|
|
if target_obj.requireApproval:
|
|
ListPendingApprovals(target_ref, active_pipeline_ref, output)
|
|
return output
|
|
|
|
|
|
def ListPendingApprovalsMultiplePipelines(target_ref, pipeline_refs, output):
|
|
"""Fetches a list of pending rollouts for each pipeline and appends the result to a single list.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target object.
|
|
pipeline_refs: protorpc.messages.Message, list of pipeline objects.
|
|
output: dictionary object
|
|
|
|
Returns:
|
|
The modified output object with the list of pending rollouts.
|
|
|
|
"""
|
|
all_pending_approvals = []
|
|
for pipeline_ref in pipeline_refs:
|
|
result_dict = ListPendingApprovals(target_ref, pipeline_ref, {})
|
|
approvals_one_pipeline = result_dict.get('Pending Approvals', [])
|
|
all_pending_approvals.extend(approvals_one_pipeline)
|
|
output['Pending Approvals'] = all_pending_approvals
|
|
return output
|
|
|
|
|
|
def SetCurrentReleaseAndRollout(current_rollout, output):
|
|
"""Set current release and the last deployment section in the output.
|
|
|
|
Args:
|
|
current_rollout: protorpc.messages.Message, rollout object.
|
|
output: dictionary object
|
|
|
|
Returns:
|
|
The modified output object with the rollout's parent release, the name of
|
|
the rollout, and the time it was deployed.
|
|
|
|
"""
|
|
if current_rollout:
|
|
current_rollout_ref = resources.REGISTRY.Parse(
|
|
current_rollout.name,
|
|
collection='clouddeploy.projects.locations.deliveryPipelines.releases.rollouts'
|
|
)
|
|
# get the name of the release associated with the current rollout.
|
|
output['Latest release'] = current_rollout_ref.Parent().RelativeName()
|
|
output['Latest rollout'] = current_rollout_ref.RelativeName()
|
|
output['Deployed'] = current_rollout.deployEndTime
|
|
|
|
return output
|
|
|
|
|
|
def ListPendingApprovals(target_ref, pipeline_ref, output):
|
|
"""Lists the rollouts in pending approval state for the specified target.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target object.
|
|
pipeline_ref: protorpc.messages.Message, pipeline object.
|
|
output: dictionary object
|
|
|
|
Returns:
|
|
The modified output object with the rollouts from the given pipeline pending
|
|
approval on the given target.
|
|
|
|
"""
|
|
try:
|
|
pending_approvals = rollout_util.ListPendingRollouts(
|
|
target_ref, pipeline_ref)
|
|
pending_approvals_names = []
|
|
for ro in pending_approvals:
|
|
pending_approvals_names.append(ro.name)
|
|
if pending_approvals_names:
|
|
output['Pending Approvals'] = pending_approvals_names
|
|
except apitools_exceptions.HttpError as error:
|
|
log.debug('Failed to list pending approvals: ' + error.content)
|
|
|
|
return output
|
|
|
|
|
|
def GetTargetDeliveryPipelines(target_ref):
|
|
"""Get all pipelines associated with a target.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target object.
|
|
|
|
Returns:
|
|
A list of delivery pipelines sorted by creation date, or an null list if
|
|
there is an error fetching the pipelines.
|
|
|
|
"""
|
|
|
|
target_dict = target_ref.AsDict()
|
|
location_ref = resources.REGISTRY.Parse(
|
|
None,
|
|
collection='clouddeploy.projects.locations',
|
|
params={
|
|
'projectsId': target_dict['projectsId'],
|
|
'locationsId': target_dict['locationsId'],
|
|
})
|
|
try:
|
|
return delivery_pipeline_util.ListDeliveryPipelinesWithTarget(
|
|
target_ref, location_ref)
|
|
except apitools_exceptions.HttpError as error:
|
|
log.warning('Failed to fetch pipelines for target: ' + error.content)
|
|
return None
|
|
|
|
|
|
def GetPipelinesAndRollouts(target_ref, pipeline_refs):
|
|
"""Retrieves the latest rollout for each delivery pipeline.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target object.
|
|
pipeline_refs: protorpc.messages.Message, pipeline object.
|
|
|
|
Returns:
|
|
A list with element [pipeline_ref, rollout] where the rollout is the latest
|
|
successful rollout of the pipeline resource.
|
|
|
|
"""
|
|
result = []
|
|
for pipeline_ref in pipeline_refs:
|
|
rollout = target_util.GetCurrentRollout(target_ref, pipeline_ref)
|
|
if rollout is not None:
|
|
result.append([pipeline_ref, rollout])
|
|
return result
|
|
|
|
|
|
def GetMostRecentlyActivePipeline(target_ref, sorted_pipeline_refs):
|
|
"""Retrieves latest rollout and release information for a list of delivery pipelines.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target object.
|
|
sorted_pipeline_refs: protorpc.messages.Message, a list of pipeline objects,
|
|
sorted in descending order by create time.
|
|
|
|
Returns:
|
|
A tuple of the pipeline with the most recent deploy time with
|
|
latest rollout.
|
|
|
|
"""
|
|
pipeline_rollouts = GetPipelinesAndRollouts(target_ref, sorted_pipeline_refs)
|
|
if not pipeline_rollouts:
|
|
log.debug('Target: {} has no recently active pipelines.'.format(
|
|
target_ref.RelativeName()))
|
|
return sorted_pipeline_refs[0], None
|
|
most_recent_pipeline_ref, most_recent_rollout = pipeline_rollouts[0]
|
|
most_recent_rollout_deploy_time = times.ParseDateTime(
|
|
most_recent_rollout.deployEndTime)
|
|
|
|
for pipeline_rollout_tuple in pipeline_rollouts[1:]:
|
|
pipeline_ref, rollout = pipeline_rollout_tuple
|
|
rollout_deploy_time = times.ParseDateTime(rollout.deployEndTime)
|
|
if rollout_deploy_time > most_recent_rollout_deploy_time:
|
|
most_recent_pipeline_ref = pipeline_ref
|
|
most_recent_rollout = rollout
|
|
most_recent_rollout_deploy_time = rollout_deploy_time
|
|
return most_recent_pipeline_ref, most_recent_rollout
|
|
|
|
|
|
def SetMostRecentlyActivePipeline(pipeline_ref, rollout):
|
|
"""Retrieves latest rollout and release information for a delivery pipeline.
|
|
|
|
Args:
|
|
pipeline_ref: protorpc.messages.Message a DeliveryPipeline object.
|
|
rollout: protorpc.messages.Message a Rollout object.
|
|
|
|
Returns:
|
|
A content directory.
|
|
|
|
"""
|
|
output = [{
|
|
pipeline_ref.RelativeName(): SetCurrentReleaseAndRollout(rollout, {})
|
|
}]
|
|
return output
|
|
|
|
|
|
def SetPipelineReleaseRollout(target_ref, pipeline_ref):
|
|
"""Retrieves latest rollout and release information for a single delivery pipeline.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target object.
|
|
pipeline_ref: protorpc.messages.Message, DeliveryPipeline object
|
|
|
|
Returns:
|
|
A content directory.
|
|
|
|
"""
|
|
|
|
current_rollout = target_util.GetCurrentRollout(target_ref, pipeline_ref)
|
|
output = {}
|
|
output = SetCurrentReleaseAndRollout(current_rollout, output)
|
|
return output
|
|
|
|
|
|
def ListAllPipelineReleaseRollout(target_ref, pipeline_refs):
|
|
"""Retrieves latest rollout and release information for each delivery pipeline.
|
|
|
|
Args:
|
|
target_ref: protorpc.messages.Message, target object.
|
|
pipeline_refs: protorpc.messages.Message a list of DeliveryPipeline objects
|
|
|
|
Returns:
|
|
A content directory.
|
|
|
|
"""
|
|
output = []
|
|
for pipeline_ref in pipeline_refs:
|
|
pipeline_entry = SetPipelineReleaseRollout(target_ref, pipeline_ref)
|
|
output.append({pipeline_ref.RelativeName(): pipeline_entry})
|
|
return output
|