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,42 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Commands for managing single tenant HSM instances."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.kms import flags
from googlecloudsdk.core import resources
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class SingleTenantHsm(base.Group):
"""Commands for managing single tenant HSM instances.
single tenant hsm instances are a new feature that allow customers to create
a dedicated HSM instance for their use.
"""
category = base.IDENTITY_AND_SECURITY_CATEGORY
@staticmethod
def Args(parser):
pass

View File

@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Create a single tenant HSM instance."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.kms import resource_args
@base.DefaultUniverseOnly
class Create(base.Command):
r"""Create a single tenant HSM instance.
## EXAMPLES
The following command creates a single tenant HSM instance
within the location `us-central1` with a total approver count of 3:
$ {command} --location=us-central1 \
--total-approver-count=3
The following command creates a single tenant HSM instance within the location
`us-central1` with a total approver count of 3, and the single tenant HSM
instance ID `my_stchi`:
$ {command} --location=us-central1 \
--total-approver-count=3 \
--single-tenant-hsm-instance-id=my_stchi
"""
@staticmethod
def Args(parser):
resource_args.AddKmsLocationResourceArgForKMS(parser, True, '--location')
parser.add_argument(
'--total-approver-count',
type=int,
required=True,
help=(
'The total number of approvers. This is the N value used for M of N'
' quorum auth. Must be greater than or equal to 3 and less than or'
' equal to 16.'
),
)
parser.add_argument(
'--single-tenant-hsm-instance-id',
type=str,
required=False,
help=(
'Specify an ID for the single tenant HSM instance. It must be'
' unique within a location and match the regular expression'
' `[a-zA-Z0-9_-]{1,63}`.'
),
)
def CreateRequest(self, args):
messages = cloudkms_base.GetMessagesModule()
location_ref = args.CONCEPTS.location.Parse()
parent = location_ref.RelativeName()
if args.total_approver_count < 3 or args.total_approver_count > 16:
raise exceptions.BadArgumentException(
'--total-approver-count',
'The total approver count must be between 3 and 16.',
)
stchi_id = (
args.single_tenant_hsm_instance_id
if args.single_tenant_hsm_instance_id
else None
)
return (
messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesCreateRequest(
parent=parent,
singleTenantHsmInstanceId=stchi_id,
singleTenantHsmInstance=messages.SingleTenantHsmInstance(
quorumAuth=messages.QuorumAuth(
totalApproverCount=int(args.total_approver_count),
),
),
)
)
def Run(self, args):
"""Create a single tenant HSM instance."""
client = cloudkms_base.GetClientInstance()
return client.projects_locations_singleTenantHsmInstances.Create(
self.CreateRequest(args)
)

View File

@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Describe a single tenant HSM instance."""
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.kms import resource_args
@base.DefaultUniverseOnly
class Describe(base.DescribeCommand):
"""Get metadata for a single tenant HSM instance.
Returns metadata for the given single tenant HSM instance.
## EXAMPLES
The following command returns the metadata for the single tenant HSM instance
with the name `my_sthi` in the location `us-east1`using the fully specified
name:
$ {command}
projects/my-project/locations/us-east1/singleTenantHsmInstances/mysthi
The following command returns the metadata for the singletenanthsm instance
with the name `mysthi` in the location `us-east1` using the location and
resource id:
$ {command} mysthi --location=us-east1
"""
@staticmethod
def Args(parser):
resource_args.AddKmsSingleTenantHsmInstanceResourceArgForKMS(
parser, True, 'single_tenant_hsm_instance'
)
def Run(self, args):
client = cloudkms_base.GetClientInstance()
messages = cloudkms_base.GetMessagesModule()
sthi_ref = args.CONCEPTS.single_tenant_hsm_instance.Parse()
if not sthi_ref.Name():
raise exceptions.InvalidArgumentException(
'single_tenant_hsm_instance',
'single_tenant_hsm_instance id must be non-empty.',
)
return client.projects_locations_singleTenantHsmInstances.Get(
messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesGetRequest(
name=sthi_ref.RelativeName()
)
)

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""List single tenant HSM instances within a 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.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.kms import resource_args
@base.DefaultUniverseOnly
class List(base.ListCommand):
r"""List single tenant HSM instances within a location.
## EXAMPLES
To list all single tenant HSM instances in a location:
$ {command} --location={location}
"""
@staticmethod
def Args(parser):
resource_args.AddKmsLocationResourceArgForKMS(parser, True, '--location')
parser.display_info.AddFormat("""
table(
name,
state,
quorum_auth.required_approver_count,
quorum_auth.total_approver_count)
""")
def Run(self, args):
"""List single tenant HSM instances."""
client = cloudkms_base.GetClientInstance()
messages = cloudkms_base.GetMessagesModule()
location_ref = args.CONCEPTS.location.Parse()
request = (
messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesListRequest(
parent=location_ref.RelativeName(),
)
)
return list_pager.YieldFromList(
client.projects_locations_singleTenantHsmInstances,
request,
field='singleTenantHsmInstances',
limit=args.limit,
batch_size=args.page_size,
batch_size_attribute='pageSize',
)

View File

@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Commands for managing single tenant HSM instances."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.kms import flags
from googlecloudsdk.core import resources
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class SingleTenantHsmInstanceProposal(base.Group):
"""Commands for managing single tenant HSM instance proposals.
single tenant hsm instance proposals represent a proposal to perform an
operation on a single tenant HSM instance.
"""
category = base.IDENTITY_AND_SECURITY_CATEGORY
@staticmethod
def Args(parser):
pass

View File

@@ -0,0 +1,226 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Approve a single tenant HSM instance proposal."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import ast
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.kms import pems
from googlecloudsdk.command_lib.kms import resource_args
from googlecloudsdk.core import exceptions as core_exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core.util import files
def tuple_list_type(arg):
try:
return ast.literal_eval(arg)
except ValueError as e:
raise exceptions.BadArgumentException(
'--challenge_replies',
'Error while attempting to parse challenge replies: {}'.format(e),
)
def _parse_challenge_replies(messages, challenge_reply_tuples):
"""Parses file paths from tuples into a list of ChallengeReply messages."""
challenge_replies = []
if not challenge_reply_tuples:
return challenge_replies
for challenge_reply in challenge_reply_tuples:
if not isinstance(challenge_reply, tuple) or len(challenge_reply) != 2:
raise exceptions.BadArgumentException(
'challenge replies',
'Each challenge reply must be a tuple of (signed_challenge_file,'
' public_key_file).',
)
signed_challenge_file, public_key_file = challenge_reply
if not signed_challenge_file:
raise exceptions.BadArgumentException(
'challenge replies',
'signed_challenge_file must be specified.',
)
if not public_key_file:
raise exceptions.BadArgumentException(
'challenge replies',
'public_key_file must be specified.',
)
try:
public_key = pems.GetPemPublicKey(public_key_file)
except Exception as e:
raise exceptions.BadArgumentException(
'challenge replies',
'Error while attempting to read public key file {}: {}'.format(
public_key_file, e
),
)
try:
signed_challenge = files.ReadBinaryFileContents(signed_challenge_file)
except Exception as e:
raise exceptions.BadArgumentException(
'challenge replies',
'Error while attempting to read signed challenge file {}: {}'.format(
signed_challenge_file, e
),
)
challenge_replies.append(
messages.ChallengeReply(
signedChallenge=signed_challenge,
publicKeyPem=public_key,
)
)
return challenge_replies
@base.DefaultUniverseOnly
class Approve(base.Command):
r"""Approve a single tenant HSM instance proposal.
## EXAMPLES
The following command approves a single tenant HSM instance proposal with
quorum challenge replies:
$ {command} projects/my-project/locations/us-east1/singleTenantHsmInstances/
my_sthi/proposals/my_proposal \
--quorum-challenge-replies="[('signed_challenge_1.txt','public_key_1.pem'),
('signed_challenge_2.txt','public_key_2.pem'),
('signed_challenge_3.txt','public_key_3.pem')]"
To approve a proposal with required challenges and quorum challenges:
$ {command} projects/my-project/locations/us-east1/singleTenantHsmInstances/
my_sthi/proposals/my_proposal \
--required-challenge-replies="[('required_challenge.txt','public_key_1.pem')]" \
--quorum-challenge-replies="[('quorum_challenge_1.txt','public_key_2.pem'),
('quorum_challenge_2.txt','public_key_3.pem')]"
"""
@staticmethod
def Args(parser):
resource_args.AddKmsSingleTenantHsmInstanceProposalResourceArgForKMS(
parser, True, 'single_tenant_hsm_instance_proposal'
)
quorum_group = parser.add_group(
required=True, help='Approval payload for the proposal.'
)
quorum_group.add_argument(
'--quorum-challenge-replies',
type=tuple_list_type,
help=(
'The challenge replies to approve the proposal. Challenge replies '
'can be sent across multiple requests. Each tuple should be '
'("signed_challenge_file", "public_key_file").'
),
)
quorum_group.add_argument(
'--required-challenge-replies',
type=tuple_list_type,
help=(
'A list of tuples, each containing the file paths for a required '
'challenge reply. Each tuple should be '
'("signed_challenge_file", "public_key_file").'
),
)
def ApproveRequest(self, args):
messages = cloudkms_base.GetMessagesModule()
single_tenant_hsm_instance_proposal_ref = (
args.CONCEPTS.single_tenant_hsm_instance_proposal.Parse()
)
kms_client = cloudkms_base.GetClientInstance()
proposal = kms_client.projects_locations_singleTenantHsmInstances_proposals.Get(
messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesProposalsGetRequest(
name=single_tenant_hsm_instance_proposal_ref.RelativeName()
)
)
approve_request = messages.ApproveSingleTenantHsmInstanceProposalRequest()
if proposal.quorumParameters is not None:
if args.quorum_challenge_replies is None:
raise exceptions.RequiredArgumentException(
'--quorum-challenge-replies',
'--quorum-challenge-replies must be specified for proposals'
' requiring quorum parameters.',
)
if args.required_challenge_replies is not None:
raise exceptions.BadArgumentException(
'--required-challenge-replies',
'This argument cannot be used with proposals requiring quorum'
' parameters.',
)
challenge_replies = _parse_challenge_replies(
messages, args.quorum_challenge_replies
)
approve_request.quorumReply = messages.QuorumReply(
challengeReplies=challenge_replies
)
elif proposal.requiredActionQuorumParameters is not None:
if (
args.required_challenge_replies is None
and args.quorum_challenge_replies is None
):
raise exceptions.RequiredArgumentException(
'--required-challenge-replies and --quorum-challenge-replies',
'At least one of --required-challenge-replies and'
' --quorum-challenge-replies must be specified for proposals'
' requiring required action quorum parameters.',
)
required_challenge_replies = _parse_challenge_replies(
messages, args.required_challenge_replies
)
quorum_challenge_replies = _parse_challenge_replies(
messages, args.quorum_challenge_replies
)
approve_request.requiredActionQuorumReply = (
messages.RequiredActionQuorumReply(
requiredChallengeReplies=required_challenge_replies,
quorumChallengeReplies=quorum_challenge_replies,
)
)
else:
raise core_exceptions.Error(
'Unsupported or missing approval parameters in proposal: {}'.format(
proposal.name
)
)
req = messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesProposalsApproveRequest(
name=single_tenant_hsm_instance_proposal_ref.RelativeName(),
approveSingleTenantHsmInstanceProposalRequest=approve_request,
)
return req
def Run(self, args):
"""Approve a single tenant HSM instance proposal."""
client = cloudkms_base.GetClientInstance()
result = (
client.projects_locations_singleTenantHsmInstances_proposals.Approve(
self.ApproveRequest(args)
)
)
if result is not Exception:
log.status.Print('Approved proposal successfully.')
return result

View File

@@ -0,0 +1,226 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Create a single tenant HSM instance proposal."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.kms import pems
from googlecloudsdk.command_lib.kms import resource_args
@base.DefaultUniverseOnly
class Create(base.Command):
r"""Create a single tenant HSM instance proposal.
$ {command}
my_stchi
--location=us-central1 \
--required-approver-count=1 \
--two-factor-public-key-pems=public_key_1.pem,public_key_2.pem
"""
@staticmethod
def Args(parser):
resource_args.AddKmsSingleTenantHsmInstanceResourceArgForKMS(
parser, True, 'single_tenant_hsm_instance'
)
parser.add_argument(
'--operation-type',
type=str,
required=True,
help=(
'The type of operation for the single tenant HSM instance proposal.'
),
)
parser.add_argument(
'--required-approver-count',
type=int,
required=False,
help=(
'The number of approvers required for the single tenant HSM'
' instance. This is the M value used for M of N quorum. Must be'
' greater than or equal to 1 and less than or equal to the total'
' approver count of the single tenant HSM instance minus 1. This'
' field is required for the register_2fa_keys operation type.'
),
)
parser.add_argument(
'--two-factor-public-key-pems',
type=arg_parsers.ArgList(),
required=False,
metavar='PEM_FILE_PATH',
help=(
'The PEM files containing the two factor public keys 2FA keys for'
' M of N quorum auth tenant HSM instance. This field is required'
' for register_2fa_keys operation type.'
),
)
parser.add_argument(
'--member-public-key-pem',
type=str,
required=False,
help=(
'The PEM file containing the public key of the quorum member to'
' add or remove. This field is required for add_quorum_member and'
' remove_quorum_member operation types.'
),
)
parser.add_argument(
'--single-tenant-hsm-instance-proposal-id',
required=False,
help=(
'The ID to use for the single tenant HSM instance proposal, which'
' will become the final component of the single tenant HSM'
' instance resource name.'
),
)
def validate_required_approver_count(self, args, messages, sthi_ref):
if args.required_approver_count is None:
raise exceptions.BadArgumentException(
'--required-approver-count',
'The required approver count must be specified for'
' register_2fa_keys operation type.',
)
get_request = (
messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesGetRequest(
name=sthi_ref.RelativeName(),
)
)
client = cloudkms_base.GetClientInstance()
sthi = client.projects_locations_singleTenantHsmInstances.Get(get_request)
max_required_approver_count = sthi.quorumAuth.totalApproverCount - 1
if (
args.required_approver_count < 2
or args.required_approver_count > max_required_approver_count
):
raise exceptions.BadArgumentException(
'--required-approver-count',
'The required approver count must be between 2 and {}.'.format(
max_required_approver_count
),
)
def public_key_pem_files_to_list(self, args):
if args.two_factor_public_key_pems is None:
raise exceptions.BadArgumentException(
'--two-factor-public-key-pems',
'The two factor public key pems must be specified for'
' register_2fa_keys operation type.',
)
pem_list = []
for pem_file in args.two_factor_public_key_pems:
try:
pem_list.append(pems.GetPemPublicKey(pem_file))
except Exception as e:
raise exceptions.BadArgumentException(
'--two-factor-public-key-pems',
'Error while attempting to read file {} : {}'.format(pem_file, e),
)
return pem_list
def CreateRequest(self, args):
messages = cloudkms_base.GetMessagesModule()
sthi_ref = args.CONCEPTS.single_tenant_hsm_instance.Parse()
sthi_proposal_id = (
args.single_tenant_hsm_instance_proposal_id
if args.single_tenant_hsm_instance_proposal_id
else None
)
req = messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesProposalsCreateRequest(
parent=sthi_ref.RelativeName(),
singleTenantHsmInstanceProposal=messages.SingleTenantHsmInstanceProposal(),
singleTenantHsmInstanceProposalId=sthi_proposal_id,
)
if args.operation_type == 'register_2fa_keys':
self.validate_required_approver_count(args, messages, sthi_ref)
pem_list = self.public_key_pem_files_to_list(args)
req.singleTenantHsmInstanceProposal.registerTwoFactorAuthKeys = (
messages.RegisterTwoFactorAuthKeys(
requiredApproverCount=args.required_approver_count,
twoFactorPublicKeyPems=pem_list,
)
)
elif args.operation_type == 'disable_sthi':
req.singleTenantHsmInstanceProposal.disableSingleTenantHsmInstance = (
messages.DisableSingleTenantHsmInstance()
)
elif args.operation_type == 'enable_sthi':
req.singleTenantHsmInstanceProposal.enableSingleTenantHsmInstance = (
messages.EnableSingleTenantHsmInstance()
)
elif args.operation_type == 'delete_sthi':
req.singleTenantHsmInstanceProposal.deleteSingleTenantHsmInstance = (
messages.DeleteSingleTenantHsmInstance()
)
elif args.operation_type == 'add_quorum_member':
if args.member_public_key_pem is None:
raise exceptions.BadArgumentException(
'--member-public-key-pem',
'The member public key must be specified for'
' add_quorum_member operation type.',
)
pem = pems.GetPemPublicKey(args.member_public_key_pem)
req.singleTenantHsmInstanceProposal.addQuorumMember = (
messages.AddQuorumMember(twoFactorPublicKeyPem=pem)
)
elif args.operation_type == 'remove_quorum_member':
if args.member_public_key_pem is None:
raise exceptions.BadArgumentException(
'--member-public-key',
'The member public key must be specified for'
' remove_quorum_member operation type.',
)
pem = pems.GetPemPublicKey(args.member_public_key_pem)
req.singleTenantHsmInstanceProposal.removeQuorumMember = (
messages.RemoveQuorumMember(twoFactorPublicKeyPem=pem)
)
elif args.operation_type == 'refresh_sthi':
req.singleTenantHsmInstanceProposal.refreshSingleTenantHsmInstance = (
messages.RefreshSingleTenantHsmInstance()
)
else:
raise exceptions.BadArgumentException(
'--operation-type',
'The operation type must be one of register_2fa_keys,'
' disable_sthi,'
' enable_sthi,'
' delete_sthi,'
' add_quorum_member,'
' remove_quorum_member, or'
' refresh_sthi.',
)
return req
def Run(self, args):
"""Create a single tenant HSM instance."""
client = cloudkms_base.GetClientInstance()
operation = (
client.projects_locations_singleTenantHsmInstances_proposals.Create(
self.CreateRequest(args)
)
)
return operation

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Delete a single tenant HSM instance proposal."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.kms import resource_args
from googlecloudsdk.core import exceptions as core_exceptions
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
class Delete(base.DeleteCommand):
r"""Delete a single tenant HSM instance proposal.
## EXAMPLES
The following command deletes a single tenant HSM instance proposal:
$ {command} projects/my-project/locations/us-east1/singleTenantHsmInstances/
my_sthi/proposals/my_proposal
"""
@staticmethod
def Args(parser):
resource_args.AddKmsSingleTenantHsmInstanceProposalResourceArgForKMS(
parser, True, 'single_tenant_hsm_instance_proposal'
)
def Run(self, args):
client = cloudkms_base.GetClientInstance()
messages = cloudkms_base.GetMessagesModule()
single_tenant_hsm_instance_proposal_ref = (
args.CONCEPTS.single_tenant_hsm_instance_proposal.Parse()
)
if not single_tenant_hsm_instance_proposal_ref.Name():
raise exceptions.InvalidArgumentException(
'singletenanthsminstanceproposal',
'singletenanthsminstanceproposal id must be non-empty.',
)
try:
result = client.projects_locations_singleTenantHsmInstances_proposals.Delete(
messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesProposalsDeleteRequest(
name=single_tenant_hsm_instance_proposal_ref.RelativeName()
)
)
log.status.Print('Deleted proposal successfully.')
return result
except exceptions.HttpException as e:
raise core_exceptions.Error('Failed to delete proposal: {}'.format(e))

View File

@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Describe a single tenant HSM instance proposal."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.kms import pems
from googlecloudsdk.command_lib.kms import resource_args
@base.DefaultUniverseOnly
class Describe(base.DescribeCommand):
r"""Get metadata for a single tenant HSM instance proposal.
## EXAMPLES
The following command returns the metadata for the single tenant HSM instance
proposal with the name `my_proposal`, of the instance `my_sthi`, and in the
location `us-east1` using the fully specified resource name.
```
$ {command} projects/my-project/locations/us-east1/singleTenantHsmInstances/
my_sthi/proposals/my_proposal
```
The following command returns the metadata for the single tenant HSM instance
proposal with the name `my_proposal`, of the instance `my_sthi`, and in the
location `us-east1` using the location, instance id, and proposal id.
```
$ {command} my_proposal --single_tenant_hsm_instance=my_sthi
--location=us-east1
```
"""
@staticmethod
def Args(parser):
resource_args.AddKmsSingleTenantHsmInstanceProposalResourceArgForKMS(
parser, True, 'single_tenant_hsm_instance_proposal'
)
def Run(self, args):
client = cloudkms_base.GetClientInstance()
messages = cloudkms_base.GetMessagesModule()
single_tenant_hsm_instance_proposal_ref = (
args.CONCEPTS.single_tenant_hsm_instance_proposal.Parse()
)
if not single_tenant_hsm_instance_proposal_ref.Name():
raise exceptions.InvalidArgumentException(
'singletenanthsminstanceproposal',
'singletenanthsminstanceproposal id must be non-empty.',
)
return client.projects_locations_singleTenantHsmInstances_proposals.Get(
messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesProposalsGetRequest(
name=single_tenant_hsm_instance_proposal_ref.RelativeName()
)
)

View File

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Executes a single tenant HSM proposal."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.kms import resource_args
@base.DefaultUniverseOnly
class Execute(base.Command):
r"""Executes a single tenant HSM proposal.
Executes a single tenant HSM proposal. The proposal must be in an approved
state.
## EXAMPLES
The following command executes a single tenant HSM proposal named
`my_proposal` associated with the single tenant HSM instance `my_sthi`
within the location `us-central1` with the fully specified name.
$ {command}
projects/my-project/locations/us-central1/singleTenantHsmInstances/
my_sthi/proposals/my_proposal
The following command executes a single tenant HSM proposal named
`my_proposal` associated with the single tenant HSM instance `my_sthi`
within the location `us-central1` using the location,
single-tenant-hsm-instance, and proposal id.
$ {command} my_proposal --location=us-central1
--single_tenant_hsm_instance=my_sthi
proposal_id=my_proposal
"""
@staticmethod
def Args(parser):
resource_args.AddKmsSingleTenantHsmInstanceProposalResourceArgForKMS(
parser, True, 'single_tenant_hsm_instance_proposal'
)
def Run(self, args):
client = cloudkms_base.GetClientInstance()
messages = cloudkms_base.GetMessagesModule()
single_tenant_hsm_instance_proposal_ref = (
args.CONCEPTS.single_tenant_hsm_instance_proposal.Parse()
)
req = messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesProposalsExecuteRequest(
name=single_tenant_hsm_instance_proposal_ref.RelativeName()
)
return client.projects_locations_singleTenantHsmInstances_proposals.Execute(
req
)

View File

@@ -0,0 +1,76 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""List single tenant HSM instances proposals within a 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.cloudkms import base as cloudkms_base
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.kms import resource_args
@base.DefaultUniverseOnly
class List(base.ListCommand):
r"""List single tenant HSM instance proposals within a single tenant HSM instance.
## EXAMPLES
To list all single tenant HSM instance proposals in a single tenant instance
using the single tenant HSM instance name `my_sthi` and the location
`us-east1`:
$ {command} my_sthi --location=us-east1
To list all single tenant HSM instance proposals in a single tenant instance
using the single tenant HSM instance name `my_sthi` and the location
`us-east1` with the full single tenant HSM instance resource name:
$ {command}
projects/my-project/locations/us-east1/singleTenantHsmInstances/my_sthi
"""
@staticmethod
def Args(parser):
resource_args.AddKmsSingleTenantHsmInstanceResourceArgForKMS(
parser, True, 'single_tenant_hsm_instance'
)
parser.display_info.AddFormat("""
table(
name,
state,
quorum_parameters.required_approver_count,
expire_time)
""")
def Run(self, args):
"""List single tenant HSM instance proposals."""
client = cloudkms_base.GetClientInstance()
messages = cloudkms_base.GetMessagesModule()
location_ref = args.CONCEPTS.single_tenant_hsm_instance.Parse()
request = messages.CloudkmsProjectsLocationsSingleTenantHsmInstancesProposalsListRequest(
parent=location_ref.RelativeName(),
)
return list_pager.YieldFromList(
client.projects_locations_singleTenantHsmInstances_proposals,
request,
field='singleTenantHsmInstanceProposals',
limit=args.limit,
batch_size=args.page_size,
batch_size_attribute='pageSize',
)