243 lines
9.8 KiB
Python
243 lines
9.8 KiB
Python
# -*- 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.
|
|
|
|
"""Command to create an HA Controller."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import textwrap
|
|
|
|
from googlecloudsdk.api_lib.compute import base_classes
|
|
from googlecloudsdk.api_lib.compute.ha_controllers import utils as api_utils
|
|
from googlecloudsdk.api_lib.compute.operations import poller
|
|
from googlecloudsdk.calliope import arg_parsers
|
|
from googlecloudsdk.calliope import base
|
|
from googlecloudsdk.command_lib.compute.ha_controllers import utils
|
|
from googlecloudsdk.command_lib.util.apis import arg_utils
|
|
from googlecloudsdk.core import exceptions as core_exceptions
|
|
from googlecloudsdk.core import log
|
|
|
|
|
|
_NODE_AFFINITY_FILE_HELP_TEXT = textwrap.dedent("""\
|
|
The JSON/YAML file containing the configuration of desired nodes onto
|
|
which instance in this zone could be scheduled. These rules filter the nodes
|
|
according to their node affinity labels. A node's affinity labels come
|
|
from the node template of the group the node is in.
|
|
|
|
The file should contain a list of a JSON/YAML objects. For an example,
|
|
see https://cloud.google.com/compute/docs/nodes/provisioning-sole-tenant-vms#configure_node_affinity_labels.
|
|
The following list describes the fields:
|
|
|
|
*key*::: Corresponds to the node affinity label keys of
|
|
the Node resource.
|
|
*operator*::: Specifies the node selection type. Must be one of:
|
|
`IN`: Requires Compute Engine to seek for matched nodes.
|
|
`NOT_IN`: Requires Compute Engine to avoid certain nodes.
|
|
*values*::: Optional. A list of values which correspond to the node
|
|
affinity label values of the Node resource.
|
|
""")
|
|
|
|
|
|
@base.DefaultUniverseOnly
|
|
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
|
|
class Create(base.CreateCommand):
|
|
"""Create an HA Controller.
|
|
|
|
Create an High Availability (HA) Controller, which helps
|
|
ensure that a virtual machine (VM) instance remains operational by
|
|
automatically managing failover across two zones.
|
|
"""
|
|
|
|
@staticmethod
|
|
def Args(parser):
|
|
base.ASYNC_FLAG.AddToParser(parser)
|
|
utils.AddHaControllerNameArgToParser(
|
|
parser, base.ReleaseTrack.ALPHA.name.lower()
|
|
)
|
|
messages = utils.GetMessagesModule('alpha')
|
|
parser.add_argument(
|
|
'--description',
|
|
help=(
|
|
'An optional, user-provided description for the HA Controller to'
|
|
' help identify its purpose.'
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
'--instance-name',
|
|
help=(
|
|
'The name of the existing VM that the HA Controller manages. This'
|
|
' VM must already exist in one of the zones specified in'
|
|
' --zone-configuration.'
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
'--failover-initiation',
|
|
required=True,
|
|
type=lambda x: arg_utils.ChoiceToEnum(
|
|
x,
|
|
messages.HaController.FailoverInitiationValueValuesEnum,
|
|
),
|
|
help=(
|
|
'Specifies how a failover is triggered. Set to MANUAL_ONLY if you'
|
|
' want to trigger failovers yourself. Must be one of:'
|
|
f' {utils.EnumTypeToChoices(messages.HaController.FailoverInitiationValueValuesEnum)}'
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
'--secondary-zone-capacity',
|
|
required=True,
|
|
type=lambda x: arg_utils.ChoiceToEnum(
|
|
x,
|
|
messages.HaController.SecondaryZoneCapacityValueValuesEnum,
|
|
),
|
|
help=(
|
|
'Determines the capacity guarantee in the secondary zone. Use'
|
|
' BEST_EFFORT to create a VM based on capacity availability at the'
|
|
' time of failover, suitable for workloads that can tolerate longer'
|
|
' recovery times. Must be one of:'
|
|
f' {utils.EnumTypeToChoices(messages.HaController.SecondaryZoneCapacityValueValuesEnum)}'
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
'--zone-configuration',
|
|
required=True,
|
|
type=arg_parsers.ArgObject(
|
|
enable_file_upload=False,
|
|
spec={
|
|
'reservation': arg_parsers.ArgObject(
|
|
value_type=str,
|
|
help_text=(
|
|
'Specifies the reservation name. The reservation must'
|
|
' exist within the HA Controller region.'
|
|
),
|
|
),
|
|
'reservation-affinity': arg_parsers.ArgObject(
|
|
value_type=lambda x: arg_utils.ChoiceToEnum(
|
|
x,
|
|
messages.HaControllerZoneConfigurationReservationAffinity.ConsumeReservationTypeValueValuesEnum,
|
|
),
|
|
help_text=(
|
|
'Specifies the reservation-affinity value.'
|
|
' Must be one of:'
|
|
f' {utils.EnumTypeToChoices(messages.HaControllerZoneConfigurationReservationAffinity.ConsumeReservationTypeValueValuesEnum)}'
|
|
),
|
|
),
|
|
'node': arg_parsers.ArgObject(
|
|
value_type=str,
|
|
help_text=(
|
|
'Specifies the node name. The node must exist within'
|
|
' the HA Controller region.'
|
|
),
|
|
),
|
|
'node-group': arg_parsers.ArgObject(
|
|
value_type=str,
|
|
help_text=(
|
|
'Specifies the node-group name. The node-group must'
|
|
' exist within the HA Controller region. Must be one'
|
|
' of:'
|
|
f' {utils.EnumTypeToChoices(messages.HaControllerZoneConfigurationNodeAffinity.OperatorValueValuesEnum)}'
|
|
),
|
|
),
|
|
'node-affinity-file': arg_parsers.ArgObject(
|
|
value_type=arg_parsers.FileContents(),
|
|
enable_file_upload=False,
|
|
help_text=_NODE_AFFINITY_FILE_HELP_TEXT,
|
|
),
|
|
'node-project': arg_parsers.ArgObject(
|
|
value_type=str,
|
|
help_text=(
|
|
'Specifies the name of the project with shared sole'
|
|
' tenant node groups to create an instance in.'
|
|
),
|
|
),
|
|
'zone': arg_parsers.ArgObject(
|
|
value_type=str,
|
|
help_text=(
|
|
'Specifies the zone. The zone must be within the HA'
|
|
' Controller region.'
|
|
),
|
|
),
|
|
},
|
|
),
|
|
action=arg_parsers.FlattenAction(),
|
|
help=(
|
|
'Configures the two zones for the HA Controller and specifies how'
|
|
' VM capacity is reserved in each zone. You must provide two zone'
|
|
' configurations. You can also specify an existing reservation or'
|
|
' node-group to guarantee capacity.'
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
'--network-auto-configuration',
|
|
required=False,
|
|
type=arg_parsers.ArgObject(
|
|
spec={
|
|
'stack-type': arg_parsers.ArgObject(
|
|
value_type=lambda x: arg_utils.ChoiceToEnum(
|
|
x,
|
|
messages.HaControllerNetworkingAutoConfigurationInternal.StackTypeValueValuesEnum),
|
|
help_text=(
|
|
'Specifies the stack type for the network'
|
|
' configuration. Must match the stack type of the'
|
|
' instance. Must be one of:'
|
|
f' {utils.EnumTypeToChoices(messages.HaControllerNetworkingAutoConfigurationInternal.StackTypeValueValuesEnum)}'
|
|
),
|
|
),
|
|
'address': arg_parsers.ArgObject(
|
|
value_type=str,
|
|
help_text=(
|
|
'Specifies an optional IPv4 address to assign to'
|
|
' the instance. If not specified, an ephemeral IP will'
|
|
' be generated.'
|
|
),
|
|
),
|
|
'internal-ipv6-address': arg_parsers.ArgObject(
|
|
value_type=str,
|
|
help_text=(
|
|
'Specifies an optional IPv6 address to assign to'
|
|
' the instance. If not specified, an ephemeral IP will'
|
|
' be generated.'
|
|
),
|
|
),
|
|
},
|
|
),
|
|
action=arg_parsers.FlattenAction(),
|
|
help=(
|
|
'Adds a network interface to the instance.'
|
|
),
|
|
)
|
|
|
|
def Run(self, args):
|
|
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
|
|
client = holder.client
|
|
ha_controller_ref = args.CONCEPTS.ha_controller.Parse()
|
|
ha_controller = client.messages.HaController(
|
|
name=ha_controller_ref.Name(),
|
|
region=ha_controller_ref.region,
|
|
description=args.description,
|
|
instanceName=args.instance_name,
|
|
failoverInitiation=args.failover_initiation,
|
|
secondaryZoneCapacity=args.secondary_zone_capacity,
|
|
zoneConfigurations=utils.MakeZoneConfiguration(args.zone_configuration),
|
|
networkingAutoConfiguration=utils.MakeNetworkConfiguration(
|
|
args.network_auto_configuration
|
|
),
|
|
)
|
|
return api_utils.Insert(
|
|
holder, ha_controller, ha_controller_ref, args.async_
|
|
)
|