456 lines
14 KiB
Python
456 lines
14 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2019 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.
|
|
"""Command line flags for Anthos commands."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
from googlecloudsdk.calliope import arg_parsers
|
|
from googlecloudsdk.calliope import base
|
|
from googlecloudsdk.core.util import files
|
|
|
|
_MERGE_STRATEGIES = {
|
|
'resource-merge': ('perform a structural comparison of the '
|
|
'original/updated Resources, and merge the changes '
|
|
'into the local package.'),
|
|
'fast-forward': ('fail without updating if the local package was modified'
|
|
' since it was fetched.'),
|
|
'alpha-git-patch': ("use 'git format-patch' and 'git am' to apply a patch "
|
|
'of the changes between the source version and '
|
|
'destination version. Requires the local package to '
|
|
'have been committed to a local git repo.'),
|
|
'force-delete-replace': ('This will wipe all local changes to the package. '
|
|
'Deletes the contents of local package from '
|
|
'PACKAGE_DIR and replace them with the remote '),
|
|
}
|
|
|
|
|
|
def GetFlagOrPositional(name, positional=False, **kwargs):
|
|
"""Return argument called name as either flag or positional."""
|
|
dest = name.replace('-', '_').upper()
|
|
if positional:
|
|
flag = dest
|
|
kwargs.pop('required', None)
|
|
else:
|
|
flag = '--{}'.format(name.replace('_', '-').lower())
|
|
if not positional:
|
|
kwargs['dest'] = dest
|
|
return base.Argument(flag, **kwargs)
|
|
|
|
|
|
def GetRepoURIFlag(positional=True,
|
|
required=True,
|
|
help_override=None,
|
|
metavar=None):
|
|
"""Get REPO_URI flag."""
|
|
help_txt = help_override or """\
|
|
Git repository URI containing 1 or more packages as where:
|
|
|
|
* REPO_URI - URI of a git repository containing 1 or more packages as
|
|
subdirectories. In most cases the .git suffix should be specified to
|
|
delimit the REPO_URI from the PKG_PATH, but this is not required for
|
|
widely recognized repo prefixes. If REPO_URI cannot be parsed then
|
|
an error will be printed an asking for '.git' to be specified
|
|
as part of the argument. e.g. https://github.com/kubernetes/examples.git
|
|
|
|
* PKG_PATH (optional) - Path to Git subdirectory containing Anthos package files.
|
|
Uses '/' as the path separator (regardless of OS). e.g. staging/cockroachdb.
|
|
Defaults to the root directory.
|
|
|
|
* GIT_REF (optional)- A git tag, branch, ref or commit for the remote version of the
|
|
package to fetch. Defaults to the repository default branch e.g. @main
|
|
"""
|
|
if not metavar:
|
|
metavar = 'REPO_URI[.git]/[PKG_PATH][@GIT_REF]'
|
|
return GetFlagOrPositional(
|
|
name='repo_uri',
|
|
positional=positional,
|
|
required=required,
|
|
help=help_txt,
|
|
metavar=metavar)
|
|
|
|
|
|
def GetPackagePathFlag(metavar=None):
|
|
return GetFlagOrPositional(
|
|
name='package_path',
|
|
positional=False,
|
|
required=False,
|
|
help="""\
|
|
Path to remote subdirectory containing Kubernetes Resource configuration
|
|
files or directories.
|
|
Defaults to the root directory.
|
|
Uses '/' as the path separator (regardless of OS).
|
|
e.g. staging/cockroachdb
|
|
""",
|
|
metavar=metavar)
|
|
|
|
|
|
def GetLocalDirFlag(positional=True,
|
|
required=True,
|
|
help_override=None,
|
|
metavar=None):
|
|
"""Get Local Package directory flag."""
|
|
help_txt = help_override or """\
|
|
The local directory to fetch the package to.
|
|
e.g. ./my-cockroachdb-copy
|
|
* If the directory does NOT exist: create the specified directory
|
|
and write the package contents to it
|
|
|
|
* If the directory DOES exist: create a NEW directory under the
|
|
specified one, defaulting the name to the Base of REPO/PKG_PATH
|
|
|
|
* If the directory DOES exist and already contains a directory with
|
|
the same name of the one that would be created: fail
|
|
"""
|
|
return GetFlagOrPositional(
|
|
name='LOCAL_DIR',
|
|
positional=positional,
|
|
required=required,
|
|
type=ExpandLocalDirAndVersion,
|
|
help=help_txt,
|
|
metavar=metavar)
|
|
|
|
|
|
def GetFilePatternFlag():
|
|
return GetFlagOrPositional(
|
|
name='pattern',
|
|
positional=False,
|
|
required=False,
|
|
help="""\
|
|
Pattern to use for writing files. May contain the following formatting
|
|
verbs %n: metadata.name, %s: metadata.namespace, %k: kind
|
|
(default "%n_%k.yaml")
|
|
""")
|
|
|
|
|
|
def GetStrategyFlag():
|
|
return base.Argument(
|
|
'--strategy',
|
|
required=False,
|
|
choices=_MERGE_STRATEGIES,
|
|
help='Controls how changes to the local package are handled.')
|
|
|
|
|
|
def GetDryRunFlag(help_override=None):
|
|
help_txt = help_override or ('If true and command fails print the '
|
|
'underlying command that was executed and '
|
|
'its exit status.')
|
|
return base.Argument(
|
|
'--dry-run', action='store_true', required=False, help=help_txt)
|
|
|
|
|
|
def GetDescriptionFlag():
|
|
return base.Argument(
|
|
'--description', required=False, help='Description of the Package.')
|
|
|
|
|
|
def GetNameFlag():
|
|
return base.Argument('--name', required=False, help='Name of the package.')
|
|
|
|
|
|
def GetTagsFlag():
|
|
return base.Argument(
|
|
'--tags',
|
|
required=False,
|
|
type=arg_parsers.ArgDict(),
|
|
metavar='TAG=VALUE',
|
|
help='Tags for the package.')
|
|
|
|
|
|
def GetInfoUrlFlag():
|
|
return base.Argument(
|
|
'--info-url',
|
|
required=False,
|
|
help='Url with more info about the package.')
|
|
|
|
|
|
def ExpandLocalDirAndVersion(directory):
|
|
"""Expand HOME relative (~) directory with optional git_ref.
|
|
|
|
Args:
|
|
directory: str, directory path in the format PATH[/][@git_ref].
|
|
|
|
Returns:
|
|
str, expanded full directory path with git_ref (if provided)
|
|
"""
|
|
path = directory.split('@') if directory else ''
|
|
full_dir = files.ExpandHomeDir(path[0])
|
|
if len(path) == 2:
|
|
full_dir += '@' + path[1]
|
|
|
|
return full_dir
|
|
|
|
|
|
# Anthos Auth
|
|
def GetClusterFlag(positional=False,
|
|
required=False,
|
|
help_override=None,
|
|
metavar=None):
|
|
"""Anthos operation cluster name flag."""
|
|
help_txt = help_override or ('Cluster to authenticate against. If no cluster '
|
|
'is specified, the command will print a list '
|
|
'of available options.')
|
|
return GetFlagOrPositional(
|
|
name='CLUSTER',
|
|
positional=positional,
|
|
required=required,
|
|
help=help_txt,
|
|
metavar=metavar)
|
|
|
|
|
|
def GetLoginConfigFlag():
|
|
return base.Argument(
|
|
'--login-config',
|
|
required=False,
|
|
help='Specifies the configuration yaml '
|
|
'file for login. Can be a file path or a URL.')
|
|
|
|
|
|
def GetLoginConfigCertFlag():
|
|
return base.Argument(
|
|
'--login-config-cert',
|
|
required=False,
|
|
type=ExpandLocalDirAndVersion,
|
|
help='Specifies the CA certificate file to be added to trusted pool '
|
|
'for making HTTPS connections to a `--login-config` URL.')
|
|
|
|
|
|
def GetUserFlag():
|
|
return base.Argument(
|
|
'--user',
|
|
required=False,
|
|
help='If configuring multiple user accounts in the same kubecconfig '
|
|
'file, you can specify a user to differentiate between them.')
|
|
|
|
|
|
def GetSetPreferredAuthenticationFlag():
|
|
return base.Argument(
|
|
'--set-preferred-auth',
|
|
required=False,
|
|
action='store_true',
|
|
help='If set, forces update of preferred '
|
|
'authentication for given cluster')
|
|
|
|
|
|
def GetServerFlag():
|
|
return base.Argument(
|
|
'--server',
|
|
required=False,
|
|
help=(
|
|
'Specifies the URL of API server of the cluster to authenticate'
|
|
' against.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetOutputDirFlag(positional=False,
|
|
required=False,
|
|
help_override=None,
|
|
metavar='OUTPUT-DIR',
|
|
default=None):
|
|
"""Anthos operation local output directory flag."""
|
|
help_txt = help_override or ('The output directory of the cluster resources.'
|
|
' If empty will export files to ./CLUSTER_NAME')
|
|
return GetFlagOrPositional(
|
|
name='OUTPUT_DIRECTORY',
|
|
positional=positional,
|
|
required=required,
|
|
type=ExpandLocalDirAndVersion,
|
|
help=help_txt,
|
|
default=default,
|
|
metavar=metavar)
|
|
|
|
|
|
def GetLocationFlag():
|
|
"""Anthos location flag."""
|
|
return base.Argument(
|
|
'--location',
|
|
required=False,
|
|
help='Specifies the Google Cloud location to use. If not'
|
|
'specified will use the current compute/zone property.')
|
|
|
|
|
|
def GetMergeFromFlag():
|
|
"""Anthos create-login-config Merge-From flag."""
|
|
return base.Argument(
|
|
'--merge-from',
|
|
required=False,
|
|
help='Specifies the file path of an existing login '
|
|
'configuration file to merge with.')
|
|
|
|
|
|
def GetConfigOutputFileFlag():
|
|
"""Anthos create-login-config output flag."""
|
|
return base.Argument(
|
|
'--output',
|
|
required=False,
|
|
type=ExpandLocalDirAndVersion,
|
|
help='Destination to write login configuration file. '
|
|
'Defaults to "kubectl-anthos-config.yaml".')
|
|
|
|
|
|
# Anthos auth token flags.
|
|
def GetTypeFlag():
|
|
"""Anthos auth token type flag, specifies the type of token to be created."""
|
|
return base.ChoiceArgument(
|
|
'--type',
|
|
required=True,
|
|
choices=['aws', 'oidc'],
|
|
help_str='Type of token to be created.')
|
|
|
|
|
|
def GetAwsStsRegionFlag():
|
|
"""Anthos auth token aws-sts-region flag, specifies the region for AWS STS endpoint for creating AWS token."""
|
|
return base.Argument(
|
|
'--aws-sts-region', required=False, help='Region for AWS STS endpoint.')
|
|
|
|
|
|
def GetTokenClusterFlag():
|
|
"""Anthos auth token cluster flag, specifies cluster name for creating AWS token."""
|
|
return base.Argument(
|
|
'--cluster',
|
|
required=False,
|
|
help='Name of the cluster for which token is created.')
|
|
|
|
|
|
def GetIdTokenFlag():
|
|
"""Anthos auth token id-token flag, specifies the ID Token received from identity provider after authorization flow."""
|
|
return base.Argument(
|
|
'--id-token',
|
|
required=False,
|
|
help='ID Token received from identity provider after authorization flow.')
|
|
|
|
|
|
def GetAccessTokenFlag():
|
|
"""Anthos auth token access-token flag, specifies the Access Token received from identity provider after authorization flow."""
|
|
return base.Argument(
|
|
'--access-token',
|
|
required=False,
|
|
help=(
|
|
'Access Token received from identity provider after authorization'
|
|
' flow.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetAccessTokenExpiryFlag():
|
|
"""Anthos auth token access-token-expiry flag, specifies the Expiration time of access token received from identity provider after authorization flow."""
|
|
return base.Argument(
|
|
'--access-token-expiry',
|
|
required=False,
|
|
help=(
|
|
'Expiration time of access token received from identity provider'
|
|
' after authorization flow. The expected format is the number of'
|
|
' seconds elapsed since January 1, 1970 UTC.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetRefreshTokenFlag():
|
|
"""Anthos auth token refresh-token flag, specifies the Refresh Token received from identity provider after authorization flow."""
|
|
return base.Argument(
|
|
'--refresh-token',
|
|
required=False,
|
|
help=(
|
|
'Refresh Token received from identity provider after authorization'
|
|
' flow.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetClientIdFlag():
|
|
"""Anthos auth token client-id flag, specifies the ClientID is the id for OIDC client application."""
|
|
return base.Argument(
|
|
'--client-id',
|
|
required=False,
|
|
help='ClientID is the id for OIDC client application.')
|
|
|
|
|
|
def GetClientSecretFlag():
|
|
"""Anthos auth token client-secret flag, specifies the Client Secret is the shared secret between OIDC client application and OIDC provider."""
|
|
return base.Argument(
|
|
'--client-secret',
|
|
required=False,
|
|
help=(
|
|
'Client Secret is the shared secret between OIDC client application'
|
|
' and OIDC provider.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetIdpCertificateAuthorityDataFlag():
|
|
"""Anthos auth token idp-certificate-authority-data flag, specifies the PEM-encoded certificate authority certificate for OIDC provider."""
|
|
return base.Argument(
|
|
'--idp-certificate-authority-data',
|
|
required=False,
|
|
help='PEM-encoded certificate authority certificate for OIDC provider.')
|
|
|
|
|
|
def GetIdpIssuerUrlFlag():
|
|
"""Anthos auth token idp-issuer-url flag, specifies the URI for the OIDC provider."""
|
|
return base.Argument(
|
|
'--idp-issuer-url',
|
|
required=False,
|
|
help=(
|
|
'URI for the OIDC provider. This URI should point to the level below'
|
|
' .well-known/openid-configuration.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetKubeconfigPathFlag():
|
|
"""Anthos auth token kubeconfig-path flag, specifies the Path to the kubeconfig path that would be updated with ID and access token on expiry."""
|
|
return base.Argument(
|
|
'--kubeconfig-path',
|
|
required=False,
|
|
help=(
|
|
'Path to the kubeconfig path that would be updated with ID and access'
|
|
' token on expiry.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetTokenUserFlag():
|
|
"""Anthos auth token user flag, specifies the User used in kubeconfig."""
|
|
return base.Argument(
|
|
'--user', required=False, help='User used in kubeconfig.'
|
|
)
|
|
|
|
|
|
def GetNoBrowserFlag():
|
|
"""Used to start authentication on a device without a browser in order to perform login on a second device with browser."""
|
|
return base.Argument(
|
|
'--no-browser',
|
|
action='store_true',
|
|
required=False,
|
|
help=(
|
|
'Option to indicate login completion on a second device with browser.'
|
|
'Used with `server` option.'
|
|
),
|
|
)
|
|
|
|
|
|
def GetRemoteBootstrapFlag():
|
|
"""Used to complete authentication that was started on a remote device without a browser, on the current device with a browser."""
|
|
return base.Argument(
|
|
'--remote-bootstrap',
|
|
required=False,
|
|
help=(
|
|
'Option to complete login that was started using `no-browser` option'
|
|
'on a remote device that does not have a browser.'
|
|
),
|
|
)
|