feat: Add new gcloud commands, API clients, and third-party libraries across various services.

This commit is contained in:
2026-01-01 20:26:35 +01:00
parent 5e23cbece0
commit a19e592eb7
25221 changed files with 8324611 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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.
"""The command group for the Cloud Batch CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
The gcloud batch command group lets you submit Batch jobs and manipulate Batch jobs and tasks.
With Batch, you can utilize the fully managed service to schedule, queue, and
execute batch jobs on Google's infrastructure.
For more information about Batch, see the
[Batch overview](https://cloud.google.com/batch)
and the
[Batch documentation](https://cloud.google.com/batch/docs/).
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
base.ReleaseTrack.GA)
class Batch(base.Group):
"""Manage Batch resources."""
detailed_help = DETAILED_HELP
category = base.BATCH_CATEGORY

View File

@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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.
"""The jobs command group for the Batch API CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
The gcloud batch jobs command group lets you submit, describe, list and delete
Batch jobs.
With Batch, you can utilize the fully managed service to schedule, queue, and
execute batch jobs on Google's infrastructure.
For more information about Batch, see the
[Batch overview](https://cloud.google.com/batch)
and the
[Batch documentation](https://cloud.google.com/batch/docs/).
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
base.ReleaseTrack.GA)
class Jobs(base.Group):
"""Manage Batch job resources."""
detailed_help = DETAILED_HELP
category = base.BATCH_CATEGORY

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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 to cancel a specified Batch job."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.batch import jobs
from googlecloudsdk.api_lib.batch import util
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.core import log
@base.UniverseCompatible
class Cancel(base.Command):
"""Cancel a job.
This command can fail for the following reasons:
* The job specified does not exist.
* The active account does not have permission to cancel the given job.
## EXAMPLES
To cancel the job with name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar
"""
@staticmethod
def Args(parser):
resource_args.AddJobResourceArgs(parser)
def Run(self, args):
release_track = self.ReleaseTrack()
client = jobs.JobsClient(release_track)
job_ref = args.CONCEPTS.job.Parse()
try:
operation = client.Cancel(job_ref)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
log.status.Print('Job {jobName} cancellation is in progress'.format(
jobName=job_ref.RelativeName()))
return operation

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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 to delete a specified Batch job."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.batch import jobs
from googlecloudsdk.api_lib.batch import util
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.core import log
class Delete(base.DeleteCommand):
"""Delete a job.
This command can fail for the following reasons:
* The job specified does not exist.
* The active account does not have permission to delete the given job.
## EXAMPLES
To delete the job with name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar
"""
@staticmethod
def Args(parser):
resource_args.AddJobResourceArgs(parser)
def Run(self, args):
release_track = self.ReleaseTrack()
client = jobs.JobsClient(release_track)
job_ref = args.CONCEPTS.job.Parse()
try:
operation = client.Delete(job_ref)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
log.status.Print('Job {jobName} deletion is in progress'.format(
jobName=job_ref.RelativeName()))
return operation

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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 to show details for a specified Batch job."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.batch import jobs
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
class Describe(base.DescribeCommand):
"""Show details of a job.
This command can fail for the following reasons:
* The job specified does not exist.
* The active account does not have permission to access the given job.
## EXAMPLES
To print details of the job with name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar
"""
@staticmethod
def Args(parser):
resource_args.AddJobResourceArgs(parser)
def Run(self, args):
release_track = self.ReleaseTrack()
client = jobs.JobsClient(release_track)
job_ref = args.CONCEPTS.job.Parse()
try:
return client.Get(job_ref)
except apitools_exceptions.HttpNotFoundError as e:
raise exceptions.HttpException(
e, error_format='Could not fetch resource: {status_message}.')

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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 to list jobs for a specified Batch project/location."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.batch import jobs
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.core import properties
@base.UniverseCompatible
class List(base.ListCommand):
"""List jobs for a specified Batch project/location.
This command can fail for the following reasons:
* The project/location specified do not exist.
* The active account does not have permission to access the given
project/location.
## EXAMPLES
To print all the jobs under all available locations for the default project,
run:
$ {command}
To print all the jobs under projects/location
`projects/foo/locations/us-central1`, run:
$ {command} --project=foo --location=us-central1
"""
@staticmethod
def Args(parser):
resource_args.AddLocationResourceArgs(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat(
'table(name, name.segment(3):label=LOCATION, status.state)'
)
def Run(self, args):
release_track = self.ReleaseTrack()
client = jobs.JobsClient(release_track)
location = args.location or properties.VALUES.batch.location.Get()
project = args.project or properties.VALUES.core.project.GetOrFail()
if location:
parent = 'projects/{}/locations/{}'.format(project, location)
else:
parent = 'projects/{}/locations/{}'.format(project, '-')
return list_pager.YieldFromList(
client.service,
client.messages.BatchProjectsLocationsJobsListRequest(
parent=parent,
pageSize=args.page_size,
),
batch_size=args.page_size,
field='jobs',
limit=args.limit,
batch_size_attribute='pageSize',
)

View File

@@ -0,0 +1,461 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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 to submit a specified Batch job."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import datetime
from apitools.base.protorpclite.messages import DecodeError
from apitools.base.py import encoding
from googlecloudsdk.api_lib.batch import jobs
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.command_lib.util.apis import arg_utils
from googlecloudsdk.core import exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core import yaml
from googlecloudsdk.core.util import files
def _CommonArgs(parser):
"""Register flags for this command.
Args:
parser: An argparse.ArgumentParser-like object. It is mocked out in order to
capture some information, but behaves like an ArgumentParser.
Returns:
network_group flag groups.
"""
network_group = parser.add_group()
network_group.add_argument(
'--network',
required=True,
type=str,
help="""The URL for the network resource.
Must specify subnetwork as well if network is specified""",
)
network_group.add_argument(
'--subnetwork',
required=True,
type=str,
help="""The URL for the subnetwork resource.
Must specify network as well if subnetwork is specified""",
)
network_group.add_argument(
'--no-external-ip-address',
action='store_true',
default=False,
help="""Required if no external public IP address
is attached to the VM. If no external public IP address,
additional configuration is required to allow the VM
to access Google Services.""",
)
task_spec_group = parser.add_group(required=True)
task_spec_group.add_argument(
'--config',
type=arg_parsers.FileContents(),
help="""The file path of the job config file in either JSON or YAML format.
It also supports direct input from stdin with '-' or HereDoc
(in shells with HereDoc support like Bash) with '- <<DELIMITER'. """,
)
runnable_group = task_spec_group.add_group(
mutex=True,
help="""Either specify the config file for the job or
the first runnable in the task spec. Specify either a script file or
container arguments for the first runnable in the task spec.""",
)
script_group = runnable_group.add_group(
mutex=True,
help="""Either specify a path to a script file to run or provide
inline text to execute directly.""",
)
script_group.add_argument(
'--script-file-path',
help="""Path to script file to run as first runnable in task spec.
File path should be a valid path on the instance volume.""",
)
script_group.add_argument(
'--script-text',
type=str,
help="""Text to run as first runnable in task spec.""",
)
container_group = runnable_group.add_group(
help="""Options to specify the container arguments for the first
runnable in the task spec."""
)
container_group.add_argument(
'--container-image-uri',
help="""The URI to pull the container image from.""",
)
container_group.add_argument(
'--container-entrypoint',
help="""Overrides the `ENTRYPOINT` specified in the container.""",
)
container_group.add_argument(
'--container-commands-file',
help="""Overrides the `CMD` specified in the container. If there is an
ENTRYPOINT (either in the container image or with the entrypoint field
below) then commands are appended as arguments to the ENTRYPOINT.""",
)
parser.add_argument(
'--priority',
type=arg_parsers.BoundedInt(0, 99),
help='Job priority [0-99] 0 is the lowest priority.',
)
parser.add_argument(
'--provisioning-model',
choices={
'STANDARD': 'The STANDARD VM provisioning model',
'SPOT': """The SPOT VM provisioning model. Ideal for fault-tolerant
workloads that can withstand preemption.""",
},
type=arg_utils.ChoiceToEnumName,
help='Specify the allowed provisioning model for the compute instances',
)
parser.add_argument(
'--machine-type',
type=str,
help="""Specify the Compute Engine machine type, for
example, e2-standard-4. Currently only one machine type is supported.""",
)
parser.add_argument(
'--job-prefix',
type=str,
help="""Specify the job prefix. A job ID in the format of
job prefix + %Y%m%d-%H%M%S will be generated. Note that job prefix
cannot be specified while JOB ID positional argument is
specified.""",
)
return network_group
def _BuildJobMsg(args, job_msg, batch_msgs):
"""Build the job API message from the args.
Args:
args: the args from the parser.
job_msg: the output job message.
batch_msgs: the related version of the batch message.
"""
if job_msg.taskGroups is None:
job_msg.taskGroups = []
if not job_msg.taskGroups:
job_msg.taskGroups.insert(
0, batch_msgs.TaskGroup(taskSpec=batch_msgs.TaskSpec(runnables=[]))
)
if args.script_file_path:
job_msg.taskGroups[0].taskSpec.runnables.insert(
0,
batch_msgs.Runnable(
script=batch_msgs.Script(path=args.script_file_path)
),
)
if args.script_text:
job_msg.taskGroups[0].taskSpec.runnables.insert(
0, batch_msgs.Runnable(script=batch_msgs.Script(text=args.script_text))
)
if (
args.container_commands_file
or args.container_image_uri
or args.container_entrypoint
):
container_cmds = []
if args.container_commands_file:
container_cmds = files.ReadFileContents(
args.container_commands_file
).splitlines()
job_msg.taskGroups[0].taskSpec.runnables.insert(
0,
batch_msgs.Runnable(
container=batch_msgs.Container(
entrypoint=args.container_entrypoint,
imageUri=args.container_image_uri,
commands=container_cmds,
)
),
)
if args.priority:
job_msg.priority = args.priority
# Add default empty allocation policy if there is no allocation policy and an
# allocation policy is needed by some other argument.
if job_msg.allocationPolicy is None and (
args.machine_type
or (args.network and args.subnetwork)
or args.provisioning_model
):
job_msg.allocationPolicy = batch_msgs.AllocationPolicy()
if args.machine_type:
if job_msg.allocationPolicy.instances is None:
job_msg.allocationPolicy.instances = []
if not job_msg.allocationPolicy.instances:
job_msg.allocationPolicy.instances.insert(
0, batch_msgs.InstancePolicyOrTemplate()
)
if job_msg.allocationPolicy.instances[0].policy is None:
job_msg.allocationPolicy.instances[0].policy = batch_msgs.InstancePolicy()
job_msg.allocationPolicy.instances[0].policy.machineType = args.machine_type
if args.network and args.subnetwork:
if job_msg.allocationPolicy.network is None:
job_msg.allocationPolicy.network = batch_msgs.NetworkPolicy(
networkInterfaces=[]
)
job_msg.allocationPolicy.network.networkInterfaces.insert(
0,
batch_msgs.NetworkInterface(
network=args.network,
subnetwork=args.subnetwork,
noExternalIpAddress=args.no_external_ip_address,
),
)
if args.provisioning_model:
if job_msg.allocationPolicy.instances is None:
job_msg.allocationPolicy.instances = []
if not job_msg.allocationPolicy.instances:
job_msg.allocationPolicy.instances.insert(
0, batch_msgs.InstancePolicyOrTemplate()
)
if job_msg.allocationPolicy.instances[0].policy is None:
job_msg.allocationPolicy.instances[0].policy = batch_msgs.InstancePolicy()
job_msg.allocationPolicy.instances[0].policy.provisioningModel = (
arg_utils.ChoiceToEnum(
args.provisioning_model,
batch_msgs.InstancePolicy.ProvisioningModelValueValuesEnum,
)
)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Submit(base.Command):
"""Submit a Batch job.
This command creates and submits a Batch job. After you create and
submit the job, Batch automatically queues, schedules, and executes it.
## EXAMPLES
To submit a job with a sample JSON configuration file (config.json) and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=config.json
To submit a job with a sample YAML configuration file (config.yaml) and
name projects/foo/locations/us-central1/jobs/bar, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=config.yaml
To submit a job through stdin with a sample job configuration and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=-
then input json job config via stdin
{
job config
}
To submit a job through HereDoc with a sample job configuration and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=- << EOF
{
job config
}
EOF
For details about how to define a job's configuration using JSON, see the
projects.locations.jobs resource in the Batch API Reference.
If you want to define a job's configuration using YAML, convert the JSON
syntax to YAML.
"""
@staticmethod
def Args(parser):
_CommonArgs(parser)
resource_args.AddSubmitJobResourceArgs(parser)
@classmethod
def _CreateJobMessage(cls, batch_msgs, config):
"""Parse into Job message using the config input.
Args:
batch_msgs: Batch defined proto message.
config: The input content being either YAML or JSON or the HEREDOC
input.
Returns:
The Parsed job message.
"""
try:
result = encoding.PyValueToMessage(batch_msgs.Job, yaml.load(config))
except (ValueError, AttributeError, yaml.YAMLParseError):
try:
result = encoding.JsonToMessage(batch_msgs.Job, config)
except (ValueError, DecodeError) as e:
raise exceptions.Error('Unable to parse config file: {}'.format(e))
return result
def Run(self, args):
job_ref = args.CONCEPTS.job.Parse()
location_ref = job_ref.Parent()
job_id = self._GetJobId(job_ref, args)
release_track = self.ReleaseTrack()
batch_client = jobs.JobsClient(release_track)
batch_msgs = batch_client.messages
job_msg = batch_msgs.Job()
if args.config:
job_msg = self._CreateJobMessage(batch_msgs, args.config)
_BuildJobMsg(args, job_msg, batch_msgs)
resp = batch_client.Create(job_id, location_ref, job_msg)
log.status.Print(
'Job {jobName} was successfully submitted.'.format(jobName=resp.uid)
)
return resp
def _GetJobId(self, job_ref, args):
job_id = job_ref.RelativeName().split('/')[-1]
if job_id != resource_args.INVALIDID and args.job_prefix:
raise exceptions.Error(
'--job-prefix cannot be specified when JOB ID positional '
'argument is specified'
)
# Remove the invalid job_id if no job_id being specified,
# batch_client would create a valid job_id.
elif args.job_prefix:
job_id = (
args.job_prefix
+ '-'
+ datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
)
# The case that both positional JOB ID and prefix are not specified
elif job_id == resource_args.INVALIDID:
job_id = None
return job_id
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class SubmitBeta(Submit):
"""Submit a Batch job.
This command creates and submits a Batch job. After you create and
submit the job, Batch automatically queues, schedules, and executes it.
## EXAMPLES
To submit a job with a sample JSON configuration file (config.json) and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=config.json
To submit a job with a sample YAML configuration file (config.yaml) and
name projects/foo/locations/us-central1/jobs/bar, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=config.yaml
To submit a job through stdin with a sample job configuration and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=-
then input json job config via stdin
{
job config
}
To submit a job through HereDoc with a sample job configuration and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=- << EOF
{
job config
}
EOF
For details about how to define a job's configuration using JSON, see the
projects.locations.jobs resource in the Batch API Reference.
If you want to define a job's configuration using YAML, convert the JSON
syntax to YAML.
"""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class SubmitAlpha(SubmitBeta):
"""Submit a Batch job.
This command creates and submits a Batch job. After you create and
submit the job, Batch automatically queues, schedules, and executes it.
## EXAMPLES
To submit a job with a sample JSON configuration file (config.json) and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=config.json
To submit a job with a sample YAML configuration file (config.yaml) and
name projects/foo/locations/us-central1/jobs/bar, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=config.yaml
To submit a job through stdin with a sample job configuration and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=-
then input json job config via stdin
{
job config
}
To submit a job through HereDoc with a sample job configuration and name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} projects/foo/locations/us-central1/jobs/bar --config=- << EOF
{
job config
}
EOF
For details about how to define a job's configuration using JSON, see the
projects.locations.jobs resource in the Batch API Reference.
If you want to define a job's configuration using YAML, convert the JSON
syntax to YAML.
"""

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""The resource allowances command group for the Batch API CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
The gcloud batch resource allowances command group lets you create, describe, list and delete
Batch resource allowances.
With Batch, you can utilize the fully managed service to schedule, queue, and
execute batch resource allowances on Google's infrastructure.
For more information about Batch, see the
[Batch overview](https://cloud.google.com/batch)
and the
[Batch documentation](https://cloud.google.com/batch/docs/).
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
@base.DefaultUniverseOnly
class ResourceAllowances(base.Group):
"""Manage Batch resource allowance resources."""
detailed_help = DETAILED_HELP
category = base.BATCH_CATEGORY

View File

@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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 to create a specified Batch resource allowance."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.protorpclite.messages import DecodeError
from apitools.base.py import encoding
from googlecloudsdk.api_lib.batch import resource_allowances
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.core import exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core import yaml
@base.DefaultUniverseOnly
class Submit(base.Command):
"""Create a Batch resource allowance.
This command creates a Batch resource allowance.
## EXAMPLES
The following command submit a resource allowance with config.json sample
config file
`projects/foo/locations/us-central1/resousrceAllowances/bar`:
$ {command} projects/foo/locations/us-central1/resousrceAllowances/bar
--config config.json
"""
@staticmethod
def Args(parser):
resource_args.AddCreateResourceAllowanceResourceArgs(parser)
parser.add_argument(
'--config',
type=arg_parsers.FileContents(),
required=True,
help="""The config file of a resource allowance.""",
)
@classmethod
def _CreateResourceAllowanceMessage(cls, batch_msgs, config):
"""Parse into ResourceAllowance message using the config input.
Args:
batch_msgs: Batch defined proto message.
config: The input content being either YAML or JSON or the HEREDOC
input.
Returns:
The Parsed resource allowance message.
"""
try:
result = encoding.PyValueToMessage(
batch_msgs.ResourceAllowance, yaml.load(config)
)
except (ValueError, AttributeError, yaml.YAMLParseError):
try:
result = encoding.JsonToMessage(batch_msgs.ResourceAllowance, config)
except (ValueError, DecodeError) as e:
raise exceptions.Error('Unable to parse config file: {}'.format(e))
return result
def Run(self, args):
resource_allowance_ref = args.CONCEPTS.resource_allowance.Parse()
location_ref = resource_allowance_ref.Parent()
resource_allowance_id = resource_allowance_ref.RelativeName().split('/')[-1]
# Remove the invalid resource_allowance_id if no resource_allowance_id
# being specified, batch_client would create a valid job_id.
if resource_allowance_id == resource_args.INVALIDID:
resource_allowance_id = None
release_track = self.ReleaseTrack()
batch_client = resource_allowances.ResourceAllowancesClient(release_track)
batch_msgs = batch_client.messages
resource_allowance_msg = batch_msgs.ResourceAllowance()
if args.config:
resource_allowance_msg = self._CreateResourceAllowanceMessage(
batch_msgs, args.config
)
resp = batch_client.Create(
resource_allowance_id, location_ref, resource_allowance_msg
)
log.status.Print(
'ResourceAllowance {resourceAllowanceName} was successfully created.'
.format(resourceAllowanceName=resp.uid)
)
return resp

View File

@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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 to delete a specified Batch resource allowance."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.batch import resource_allowances
from googlecloudsdk.api_lib.batch import util
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.core import log
class Delete(base.DeleteCommand):
"""Delete a Batch resource allowance.
This command can fail for the following reasons:
* The resource allowance specified does not exist.
* The active account does not have permission to delete the given resource
allowance.
## EXAMPLES
To delete the resource allowance with name
`projects/foo/locations/us-central1/resourceAllowances/bar`, run:
$ {command} projects/foo/locations/us-central1/resourceAllowances/bar
"""
@staticmethod
def Args(parser):
resource_args.AddResourceAllowanceResourceArgs(parser)
def Run(self, args):
release_track = self.ReleaseTrack()
client = resource_allowances.ResourceAllowancesClient(release_track)
resource_allowance_ref = args.CONCEPTS.resource_allowance.Parse()
try:
operation = client.Delete(resource_allowance_ref)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
log.status.Print(
'ResourceAllowance {resourceAllowanceName} deletion is in progress'
.format(resourceAllowanceName=resource_allowance_ref.RelativeName())
)
return operation

View File

@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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 to show details for a specified Batch resource allowance."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.batch import resource_allowances
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
class Describe(base.DescribeCommand):
"""Show details of a resource allowance.
This command can fail for the following reasons:
* The resource allowance specified does not exist.
* The active account does not have permission to access the given resource
allowance.
## EXAMPLES
To print details of the resource allowance with name
`projects/foo/locations/us-central1/resourceAllowances/bar`, run:
$ {command} projects/foo/locations/us-central1/resourceAllowances/bar
"""
@staticmethod
def Args(parser):
resource_args.AddResourceAllowanceResourceArgs(parser)
def Run(self, args):
release_track = self.ReleaseTrack()
client = resource_allowances.ResourceAllowancesClient(release_track)
resource_allowance_ref = args.CONCEPTS.resource_allowance.Parse()
try:
return client.Get(resource_allowance_ref)
except apitools_exceptions.HttpNotFoundError as e:
raise exceptions.HttpException(
e, error_format='Could not fetch resource: {status_message}.')

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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 to list resource allowances for a specified Batch project/location."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.batch import resource_allowances
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.core import properties
class List(base.ListCommand):
"""List resource allowances for a specified Batch project/location.
This command can fail for the following reasons:
* The project/location specified do not exist.
* The active account does not have permission to access the given
project/location.
## EXAMPLES
To print all the resource allowances under all available locations for the
default project,
run:
$ {command}
To print all the resource allowances under projects/location
`projects/foo/locations/us-central1`, run:
$ {command} --project=foo --location=us-central1
"""
@staticmethod
def Args(parser):
resource_args.AddLocationResourceArgs(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat(
'table(name, name.segment(3):label=LOCATION,'
' usageResourceAllowance.status.state)'
)
def Run(self, args):
release_track = self.ReleaseTrack()
client = resource_allowances.ResourceAllowancesClient(release_track)
location = args.location or properties.VALUES.batch.location.Get()
project = args.project or properties.VALUES.core.project.GetOrFail()
if location:
parent = 'projects/{}/locations/{}'.format(project, location)
else:
parent = 'projects/{}/locations/{}'.format(project, '-')
return list_pager.YieldFromList(
client.service,
client.messages.BatchProjectsLocationsResourceAllowancesListRequest(
parent=parent, pageSize=args.page_size
),
batch_size=args.page_size,
field='resourceAllowances',
limit=args.limit,
batch_size_attribute='pageSize',
)

View File

@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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 to update a specified Batch resource allowance."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.batch import resource_allowances
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
from googlecloudsdk.core import exceptions
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
class Update(base.Command):
"""Update a Batch resource allowance.
This command updates a Batch resource allowance.
## EXAMPLES
The following command updates a resource allowance limit to 0
`projects/foo/locations/us-central1/resousrceAllowances/bar`:
$ {command} projects/foo/locations/us-central1/resousrceAllowances/bar
--usage-limit 0
"""
@staticmethod
def Args(parser):
resource_args.AddResourceAllowanceResourceArgs(parser)
parser.add_argument(
'--usage-limit',
help="""Limit value of a UsageResourceAllowance within its one
duration. Limit cannot be a negative value. Default is 0.""",
)
def Run(self, args):
update_mask = self.GenerateUpdateMask(args)
if len(update_mask) < 1:
raise exceptions.Error(
'Update commands must specify at least one additional parameter to'
' change.'
)
release_track = self.ReleaseTrack()
batch_client = resource_allowances.ResourceAllowancesClient(release_track)
resource_allowance_ref = args.CONCEPTS.resource_allowance.Parse()
batch_msgs = batch_client.messages
resource_allowance_msg = batch_msgs.ResourceAllowance()
if args.IsSpecified('usage_limit'):
setattr(
resource_allowance_msg,
'usageResourceAllowance',
batch_msgs.UsageResourceAllowance(
spec=(
batch_msgs.UsageResourceAllowanceSpec(
limit=batch_msgs.Limit(
limit=float(args.usage_limit)
)
)
)
),
)
resp = batch_client.Update(
resource_allowance_ref, resource_allowance_msg, update_mask
)
log.status.Print(
'ResourceAllowance {resourceAllowanceName} was successfully updated.'
.format(resourceAllowanceName=resp.uid)
)
return resp
def GenerateUpdateMask(self, args):
"""Create Update Mask for ResourceAllowances."""
update_mask = []
if args.IsSpecified('usage_limit'):
update_mask.append('usageResourceAllowance.spec.limit.limit')
return update_mask

View File

@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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.
"""The tasks command group for the Batch API CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
The gcloud batch tasks command group lets you describe and list Batch tasks.
With Batch, you can utilize the fully managed service to schedule, queue, and
execute batch jobs on Google's infrastructure.
For more information about Batch, see the
[Batch overview](https://cloud.google.com/batch)
and the
[Batch documentation](https://cloud.google.com/batch/docs/).
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
base.ReleaseTrack.GA)
class Tasks(base.Group):
"""Manage Batch task resources."""
detailed_help = DETAILED_HELP
category = base.BATCH_CATEGORY

View File

@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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 to show details for a specified Batch task."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.batch import tasks
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
class Describe(base.DescribeCommand):
"""Show details of a task.
This command can fail for the following reasons:
* The task specified does not exist.
* The active account does not have permission to access the given task.
## EXAMPLES
To print details of the task with name
`projects/foo/locations/us-central1/jobs/bar/taskGroups/group0/tasks/0`, run:
$ {command}
projects/foo/locations/us-central1/jobs/bar/taskGroups/group0/tasks/0
"""
@staticmethod
def Args(parser):
resource_args.AddTaskResourceArgs(parser)
def Run(self, args):
release_track = self.ReleaseTrack()
client = tasks.TasksClient(release_track)
task_ref = args.CONCEPTS.task.Parse()
try:
return client.Get(task_ref)
except apitools_exceptions.HttpNotFoundError as e:
raise exceptions.HttpException(
e, error_format='Could not fetch resource: {status_message}.')

View File

@@ -0,0 +1,127 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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 to list tasks for a specified Batch job."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.batch import tasks
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.batch import resource_args
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA)
@base.UniverseCompatible
class List(base.ListCommand):
"""List tasks for a specified Batch job.
Currently, since Batch only supports one taskGroup, group0, the command
takes --job as the required argument and will list all tasks
in group0 of the job.
This command can fail for the following reasons:
* The job specified does not exist.
* The active account does not have permission to access the given job
## EXAMPLES
To print all tasks in the job with name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} --job projects/foo/locations/us-central1/jobs/bar
"""
@staticmethod
def Args(parser):
resource_args.AddJobFlagResourceArgs(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat('table(name, status.state)')
def Run(self, args):
release_track = self.ReleaseTrack()
client = tasks.TasksClient(release_track)
job_ref = args.CONCEPTS.job.Parse()
return list_pager.YieldFromList(
client.service,
client.messages.BatchProjectsLocationsJobsTaskGroupsTasksListRequest(
parent=job_ref.RelativeName() + '/taskGroups/group0',
pageSize=args.page_size,
filter=args.filter,
),
batch_size=args.page_size,
field='tasks',
limit=args.limit,
batch_size_attribute='pageSize',
)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
@base.UniverseCompatible
class ListAlpha(base.ListCommand):
"""List tasks for a specified Batch job.
Currently, since Batch only supports one taskGroup, group0, the command
takes --job as the required argument and will list all tasks
in group0 of the job.
This command can fail for the following reasons:
* The job specified does not exist.
* The active account does not have permission to access the given job
## EXAMPLES
To print all tasks in the job with name
`projects/foo/locations/us-central1/jobs/bar`, run:
$ {command} --job projects/foo/locations/us-central1/jobs/bar
"""
@staticmethod
def Args(parser):
resource_args.AddJobFlagResourceArgs(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat('table(name, status.state)')
def Run(self, args):
"""Alpha version method to list tasks for a specified Batch job.
Args:
args: The command line arguments of the list command including job
resource, page size, filter, limit and sort-by.
Returns:
The list of tasks for the job.
"""
release_track = self.ReleaseTrack()
client = tasks.TasksClient(release_track)
job_ref = args.CONCEPTS.job.Parse()
return list_pager.YieldFromList(
client.service,
client.messages.BatchProjectsLocationsJobsTaskGroupsTasksListRequest(
parent=job_ref.RelativeName() + '/taskGroups/group0',
pageSize=args.page_size,
),
batch_size=args.page_size,
field='tasks',
limit=args.limit,
batch_size_attribute='pageSize',
)