1# -*- coding: utf-8 -*- #
2# Copyright 2017 Google LLC. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#    http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""Command for listing available services."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import unicode_literals
20
21from googlecloudsdk.api_lib.run import global_methods
22from googlecloudsdk.calliope import base
23from googlecloudsdk.command_lib.run import commands
24from googlecloudsdk.command_lib.run import connection_context
25from googlecloudsdk.command_lib.run import flags
26from googlecloudsdk.command_lib.run import platforms
27from googlecloudsdk.command_lib.run import pretty_print
28from googlecloudsdk.command_lib.run import resource_args
29from googlecloudsdk.command_lib.run import serverless_operations
30from googlecloudsdk.command_lib.util.concepts import concept_parsers
31from googlecloudsdk.command_lib.util.concepts import presentation_specs
32from googlecloudsdk.core import log
33from googlecloudsdk.core import properties
34
35
36@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.GA)
37class List(commands.List):
38  """List available services."""
39
40  detailed_help = {
41      'DESCRIPTION': """\
42          {description}
43          """,
44      'EXAMPLES': """\
45          To list available services:
46
47              $ {command}
48          """,
49  }
50
51  @classmethod
52  def CommonArgs(cls, parser):
53    # Flags specific to connecting to a cluster
54    cluster_group = flags.GetClusterArgGroup(parser)
55    namespace_presentation = presentation_specs.ResourcePresentationSpec(
56        '--namespace',
57        resource_args.GetNamespaceResourceSpec(),
58        'Namespace to list services in.',
59        required=True,
60        prefixes=False)
61    concept_parsers.ConceptParser(
62        [namespace_presentation]).AddToParser(cluster_group)
63
64    parser.display_info.AddUriFunc(cls._GetResourceUri)
65
66  @classmethod
67  def Args(cls, parser):
68    cls.CommonArgs(parser)
69
70  def _SetFormat(self, args, show_region=False, show_namespace=False):
71    """Set display format for output.
72
73    Args:
74      args: Namespace, the args namespace
75      show_region: bool, True to show region of listed services
76      show_namespace: bool, True to show namespace of listed services
77    """
78    columns = [
79        pretty_print.READY_COLUMN,
80        'firstof(id,metadata.name):label=SERVICE',
81    ]
82    if show_region:
83      columns.append('region:label=REGION')
84    if show_namespace:
85      columns.append('namespace:label=NAMESPACE')
86    columns.extend([
87        'domain:label=URL',
88        'last_modifier:label="LAST DEPLOYED BY"',
89        'last_transition_time:label="LAST DEPLOYED AT"',
90    ])
91    args.GetDisplayInfo().AddFormat(
92        'table({})'.format(','.join(columns)))
93
94  def Run(self, args):
95    """List available services."""
96    is_managed = platforms.GetPlatform() == platforms.PLATFORM_MANAGED
97    if is_managed and not args.IsSpecified('region'):
98      self._SetFormat(args, show_region=True)
99      client = global_methods.GetServerlessClientInstance()
100      self.SetPartialApiEndpoint(client.url)
101      args.CONCEPTS.namespace.Parse()  # Error if no proj.
102      # Don't consider region property here, we'll default to all regions
103      return commands.SortByName(global_methods.ListServices(client))
104    else:
105      conn_context = connection_context.GetConnectionContext(
106          args, flags.Product.RUN, self.ReleaseTrack())
107      self._SetFormat(
108          args, show_region=is_managed, show_namespace=(not is_managed))
109      namespace_ref = args.CONCEPTS.namespace.Parse()
110      with serverless_operations.Connect(conn_context) as client:
111        self.SetCompleteApiEndpoint(conn_context.endpoint)
112        if not is_managed:
113          location_msg = ' in [{}]'.format(conn_context.cluster_location)
114          project_msg = ' in project [{}]'.format(conn_context.cluster_project)
115          is_multi_tenant = conn_context.cluster_project != properties.VALUES.core.project.Get(
116              required=False)
117          log.status.Print('For cluster [{cluster}]{zone}{project}:'.format(
118              cluster=conn_context.cluster_name,
119              zone=location_msg if conn_context.cluster_location else '',
120              project=project_msg if is_multi_tenant else ''))
121        return commands.SortByName(client.ListServices(namespace_ref))
122
123
124@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
125class AlphaList(List):
126  """List available services."""
127
128  @classmethod
129  def Args(cls, parser):
130    cls.CommonArgs(parser)
131
132AlphaList.__doc__ = List.__doc__
133