1# -*- coding: utf-8 -*- #
2# Copyright 2019 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 line flags for Anthos commands."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import unicode_literals
20
21from googlecloudsdk.calliope import arg_parsers
22from googlecloudsdk.calliope import base
23from googlecloudsdk.core.util import files
24
25
26_MERGE_STRATEGIES = {
27    'resource-merge': ('perform a structural comparison of the '
28                       'original/updated Resources, and merge the changes '
29                       'into the local package.'),
30    'fast-forward': ('fail without updating if the local package was modified'
31                     ' since it was fetched.'),
32    'alpha-git-patch': ("use 'git format-patch' and 'git am' to apply a patch "
33                        "of the changes between the source version and "
34                        "destination version. Requires the local package to "
35                        "have been committed to a local git repo."),
36    'force-delete-replace': ('This will wipe all local changes to the package. '
37                             'Deletes the contents of local package from '
38                             'PACKAGE_DIR and replace them with the remote '),
39}
40
41
42def GetFlagOrPositional(name, positional=False, **kwargs):
43  """Return argument called name as either flag or positional."""
44  dest = name.replace('-', '_').upper()
45  if positional:
46    flag = dest
47    kwargs.pop('required', None)
48  else:
49    flag = '--{}'.format(name.replace('_', '-').lower())
50  if not positional:
51    kwargs['dest'] = dest
52  return base.Argument(flag, **kwargs)
53
54
55def GetRepoURIFlag(positional=True, required=True,
56                   help_override=None, metavar=None):
57  """Get REPO_URI flag."""
58  help_txt = help_override or """\
59      Git repository URI containing 1 or more packages as where:
60
61      * REPO_URI - URI of a git repository containing 1 or more packages as
62        subdirectories. In most cases the .git suffix should be specified to
63        delimit the REPO_URI from the PKG_PATH, but this is not required for
64        widely recognized repo prefixes.  If REPO_URI cannot be parsed then
65        an error will be printed an asking for '.git' to be specified
66        as part of the argument. e.g. https://github.com/kubernetes/examples.git
67
68      * PKG_PATH (optional) - Path to Git subdirectory containing Anthos package files.
69       Uses '/' as the path separator (regardless of OS). e.g. staging/cockroachdb.
70       Defaults to the root directory.
71
72      * GIT_REF (optional)- A git tag, branch, ref or commit for the remote version of the
73        package to fetch. Defaults to the repository master branch e.g. @master
74  """
75  if not metavar:
76    metavar = 'REPO_URI[.git]/[PKG_PATH][@GIT_REF]'
77  return GetFlagOrPositional(
78      name='repo_uri',
79      positional=positional,
80      required=required,
81      help=help_txt,
82      metavar=metavar)
83
84
85def GetPackagePathFlag(metavar=None):
86  return GetFlagOrPositional(
87      name='package_path',
88      positional=False,
89      required=False,
90      help="""\
91      Path to remote subdirectory containing Kubernetes Resource configuration
92      files or directories.
93      Defaults to the root directory.
94      Uses '/' as the path separator (regardless of OS).
95      e.g. staging/cockroachdb
96      """,
97      metavar=metavar)
98
99
100def GetLocalDirFlag(positional=True, required=True,
101                    help_override=None, metavar=None):
102  """Get Local Package directory flag."""
103  help_txt = help_override or """\
104      The local directory to fetch the package to.
105      e.g. ./my-cockroachdb-copy
106      * If the directory does NOT exist: create the specified directory
107        and write the package contents to it
108
109      * If the directory DOES exist: create a NEW directory under the
110        specified one, defaulting the name to the Base of REPO/PKG_PATH
111
112      * If the directory DOES exist and already contains a directory with
113        the same name of the one that would be created: fail
114      """
115  return GetFlagOrPositional(
116      name='LOCAL_DIR',
117      positional=positional,
118      required=required,
119      type=ExpandLocalDirAndVersion,
120      help=help_txt,
121      metavar=metavar)
122
123
124def GetFilePatternFlag():
125  return GetFlagOrPositional(
126      name='pattern',
127      positional=False,
128      required=False,
129      help="""\
130      Pattern to use for writing files. May contain the following formatting
131      verbs %n: metadata.name, %s: metadata.namespace, %k: kind
132      (default "%n_%k.yaml")
133      """)
134
135
136def GetStrategyFlag():
137  return base.Argument(
138      '--strategy',
139      required=False,
140      choices=_MERGE_STRATEGIES,
141      help='Controls how changes to the local package are handled.')
142
143
144def GetDryRunFlag(help_override=None):
145  help_txt = help_override or ('If true and command fails print the '
146                               'underlying command that was executed and '
147                               'its exit status.')
148  return base.Argument(
149      '--dry-run',
150      action='store_true',
151      required=False,
152      help=help_txt)
153
154
155def GetDescriptionFlag():
156  return base.Argument(
157      '--description',
158      required=False,
159      help='Description of the Package.')
160
161
162def GetNameFlag():
163  return base.Argument(
164      '--name',
165      required=False,
166      help='Name of the package.')
167
168
169def GetTagsFlag():
170  return base.Argument(
171      '--tags',
172      required=False,
173      type=arg_parsers.ArgDict(),
174      metavar='TAG=VALUE',
175      help='Tags for the package.')
176
177
178def GetInfoUrlFlag():
179  return base.Argument(
180      '--info-url',
181      required=False,
182      help='Url with more info about the package.')
183
184
185def ExpandLocalDirAndVersion(directory):
186  """Expand HOME relative (~) directory with optional git_ref.
187
188  Args:
189      directory: str, directory path in the format PATH[/][@git_ref].
190  Returns:
191      str, expanded full directory path with git_ref (if provided)
192  """
193  path = directory.split('@') if directory else ''
194  full_dir = files.ExpandHomeDir(path[0])
195  if len(path) == 2:
196    full_dir += '@' + path[1]
197
198  return full_dir
199
200
201# Anthos Auth
202def GetClusterFlag(positional=False, required=False,
203                   help_override=None, metavar=None):
204  """Anthos operation cluster name flag."""
205  help_txt = help_override or ('Cluster to authenticate against. If no cluster '
206                               'is specified, the command will print a list '
207                               'of available options.')
208  return GetFlagOrPositional(
209      name='CLUSTER',
210      positional=positional,
211      required=required,
212      help=help_txt,
213      metavar=metavar)
214
215
216def GetLoginConfigFlag():
217  return base.Argument(
218      '--login-config',
219      required=False,
220      help='Specifies the configuration yaml '
221           'file for login. Can be a file path or a URL.')
222
223
224def GetLoginConfigCertFlag():
225  return base.Argument(
226      '--login-config-cert',
227      required=False,
228      type=ExpandLocalDirAndVersion,
229      help='Specifies the CA certificate file to be added to trusted pool '
230           'for making HTTPS connections to a `--login-config` URL.')
231
232
233def GetUserFlag():
234  return base.Argument(
235      '--user',
236      required=False,
237      help='If configuring multiple user accounts in the same kubecconfig '
238           'file, you can specify a user to differentiate between them.')
239
240
241def GetSetPreferredAuthenticationFlag():
242  return base.Argument(
243      '--set-preferred-auth',
244      required=False,
245      action='store_true',
246      help='If set, forces update of preferred '
247           'authentication for given cluster')
248
249
250def GetOutputDirFlag(positional=False, required=False,
251                     help_override=None, metavar='OUTPUT-DIR', default=None):
252  """Anthos operation local output directory flag."""
253  help_txt = help_override or ('The output directory of the cluster resources.'
254                               ' If empty will export files to ./CLUSTER_NAME')
255  return GetFlagOrPositional(
256      name='OUTPUT_DIRECTORY',
257      positional=positional,
258      required=required,
259      type=ExpandLocalDirAndVersion,
260      help=help_txt,
261      default=default,
262      metavar=metavar)
263
264
265def GetLocationFlag():
266  """Anthos location flag."""
267  return base.Argument(
268      '--location',
269      required=False,
270      help='Specifies the Google Cloud location to use. If not'
271           'specified will use the current compute/zone property.')
272
273
274def GetMergeFromFlag():
275  """Anthos create-login-config Merge-From flag."""
276  return base.Argument(
277      '--merge-from',
278      required=False,
279      help='Specifies the file path of an existing login '
280           'configuration file to merge with.')
281
282
283def GetConfigOutputFileFlag():
284  """Anthos create-login-config output flag."""
285  return base.Argument(
286      '--output',
287      required=False,
288      type=ExpandLocalDirAndVersion,
289      help='Destination to write login configuration file. '
290           'Defaults to "kubectl-anthos-config.yaml".')
291