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,50 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 reading and manipulating instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA)
class InstanceGroups(base.Group):
"""Read and manipulate Compute Engine instance groups.
Read and manipulate Compute Engine instance groups. To accommodate the
differences between managed and unmanaged instances, some commands (such as
`delete`) are in the managed or unmanaged subgroups.
"""
InstanceGroups.category = base.INSTANCES_CATEGORY
InstanceGroups.detailed_help = {
'DESCRIPTION': """
Read and manipulate Compute Engine instance groups.
To accommodate the differences between managed and unmanaged instances,
some commands (such as `delete`) are in the managed or unmanaged
subgroups.
For more information about instance groups, see the
[instance groups documentation](https://cloud.google.com/compute/docs/instance-groups/).
See also: [Instance groups API](https://cloud.google.com/compute/docs/reference/rest/v1/instanceGroups).
""",
}

View File

@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for describing instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags
class Describe(base.DescribeCommand):
"""Display detailed information about an instance group."""
@staticmethod
def Args(parser):
flags.MULTISCOPE_INSTANCE_GROUP_ARG.AddArgument(
parser, operation_type='describe')
def Collection(self):
return 'compute.instanceGroups'
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client.apitools_client
messages = holder.client.messages
ref = flags.MULTISCOPE_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
scope_lister=compute_flags.GetDefaultScopeLister(holder.client))
if ref.Collection() == 'compute.instanceGroups':
service = client.instanceGroups
request_type = messages.ComputeInstanceGroupsGetRequest
elif ref.Collection() == 'compute.regionInstanceGroups':
service = client.regionInstanceGroups
request_type = messages.ComputeRegionInstanceGroupsGetRequest
return service.Get(request_type(**ref.AsDict()))
Describe.detailed_help = base_classes.GetMultiScopeDescriberHelp(
'instance group', (base_classes.ScopeType.regional_scope,
base_classes.ScopeType.zonal_scope))

View File

@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for listing named ports in instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
class GetNamedPortsBeta(base.ListCommand):
"""Implements get-named-ports command, alpha, and beta versions."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat('table(name, port)')
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.AddArgument(parser)
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""Retrieves response with named ports."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
group_ref = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(holder.client)))
return instance_groups_utils.OutputNamedPortsForGroup(
group_ref, holder.client)
detailed_help = (
instance_groups_utils.INSTANCE_GROUP_GET_NAMED_PORT_DETAILED_HELP)

View File

@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for listing instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.api_lib.compute import lister
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import completers
def _Args(parser):
"""Adds flags common to all release tracks."""
parser.display_info.AddFormat("""\
table(
name,
location():label=LOCATION,
location_scope():label=SCOPE,
network.basename(),
isManaged:label=MANAGED,
size:label=INSTANCES
)""")
lister.AddMultiScopeListerFlags(parser, zonal=True, regional=True)
parser.display_info.AddCacheUpdater(completers.InstanceGroupsCompleter)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class List(base.ListCommand):
"""List Compute Engine instance groups."""
@staticmethod
def Args(parser):
_Args(parser)
managed_args_group = parser.add_mutually_exclusive_group()
managed_args_group.add_argument(
'--only-managed',
action='store_true',
help='If provided, a list of managed instance groups will be returned.')
managed_args_group.add_argument(
'--only-unmanaged',
action='store_true',
help=('If provided, a list of unmanaged instance groups '
'will be returned.'))
def ComputeDynamicProperties(self, args, items, holder):
mode = instance_groups_utils.InstanceGroupFilteringMode.ALL_GROUPS
if args.only_managed:
mode = (
instance_groups_utils.InstanceGroupFilteringMode.ONLY_MANAGED_GROUPS)
elif args.only_unmanaged:
mode = (
instance_groups_utils.InstanceGroupFilteringMode.ONLY_UNMANAGED_GROUPS
)
return instance_groups_utils.ComputeInstanceGroupManagerMembership(
compute_holder=holder, items=items, filter_mode=mode)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
request_data = lister.ParseMultiScopeFlags(
args, holder.resources, holder.client.messages.InstanceGroup)
list_implementation = lister.MultiScopeLister(
client,
zonal_service=client.apitools_client.instanceGroups,
regional_service=client.apitools_client.regionInstanceGroups,
aggregation_service=client.apitools_client.instanceGroups)
return self.ComputeDynamicProperties(
args, lister.Invoke(request_data, list_implementation), holder)
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class ListBeta(List):
"""List Compute Engine managed instance groups."""
@staticmethod
def Args(parser):
_Args(parser)
def ComputeDynamicProperties(self, args, items, holder):
return instance_groups_utils.ComputeInstanceGroupManagerMembership(
compute_holder=holder,
items=items,
filter_mode=instance_groups_utils.InstanceGroupFilteringMode.ALL_GROUPS)
List.detailed_help = base_classes.GetMultiScopeListerHelp(
'instance groups',
(base_classes.ScopeType.regional_scope, base_classes.ScopeType.zonal_scope))
ListBeta.detailed_help = List.detailed_help

View File

@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for listing instances in instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.api_lib.compute import request_helper
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
class ListInstances(base.ListCommand):
"""List Compute Engine instances present in instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""\
table(instance.basename():label=NAME,
instance.scope().segment(0):label=ZONE,
status)""")
parser.display_info.AddUriFunc(
instance_groups_utils.UriFuncForListInstanceRelatedObjects)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.AddArgument(parser)
flags.AddRegexArg(parser)
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""Retrieves response with instance in the instance group."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client)))
if args.regexp:
# Regexp interprested as RE2 by Instance Group API
filter_expr = 'instance eq {0}'.format(args.regexp)
else:
filter_expr = None
if group_ref.Collection() == 'compute.instanceGroups':
service = client.apitools_client.instanceGroups
request = client.messages.ComputeInstanceGroupsListInstancesRequest(
instanceGroup=group_ref.Name(),
instanceGroupsListInstancesRequest=(
client.messages.InstanceGroupsListInstancesRequest()),
zone=group_ref.zone,
filter=filter_expr,
project=group_ref.project)
else:
service = client.apitools_client.regionInstanceGroups
request = client.messages.ComputeRegionInstanceGroupsListInstancesRequest(
instanceGroup=group_ref.Name(),
regionInstanceGroupsListInstancesRequest=(
client.messages.RegionInstanceGroupsListInstancesRequest()),
region=group_ref.region,
filter=filter_expr,
project=group_ref.project)
errors = []
results = request_helper.MakeRequests(
requests=[(service, 'ListInstances', request)],
http=client.apitools_client.http,
batch_url=client.batch_url,
errors=errors)
if errors:
utils.RaiseToolException(errors)
return results
ListInstances.detailed_help = {
'brief':
'List instances present in the instance group',
'DESCRIPTION':
"""\
*{command}* list instances in an instance group.
The required permission to execute this command is
`compute.instanceGroups.list`. If needed, you can include this
permission, or choose any of the following preexisting IAM roles
that contain this particular permission:
* Compute Admin
* Compute Viewer
* Compute Instance Admin (v1)
* Compute Instance Admin (beta)
* Compute Network Admin
* Compute Network Viewer
* Editor
* Owner
* Security Reviewer
* Viewer
For more information regarding permissions required by
instance groups, refer to Compute Engine's access control guide:
https://cloud.google.com/compute/docs/access/iam.
""",
}

View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 reading and manipulating managed instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class ManagedInstanceGroups(base.Group):
"""Read and manipulate Compute Engine managed instance groups."""
ManagedInstanceGroups.detailed_help = {
'brief': (
'Read and manipulate Compute Engine managed instance groups'),
}

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for abandoning instances owned by a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
class AbandonInstances(base.Command):
"""Abandon instances owned by a managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(project(),
zone(),
instanceName:label=INSTANCE,
status)""")
parser.add_argument('--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
required=True,
help='Names of instances to abandon.')
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instances_holder_field = 'instanceGroupManagersAbandonInstancesRequest'
request = client.messages.ComputeInstanceGroupManagersAbandonInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersAbandonInstancesRequest=client.messages
.InstanceGroupManagersAbandonInstancesRequest(instances=[]),
project=igm_ref.project,
zone=igm_ref.zone)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instances_holder_field = 'regionInstanceGroupManagersAbandonInstancesRequest'
request = client.messages.ComputeRegionInstanceGroupManagersAbandonInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersAbandonInstancesRequest=client.messages
.RegionInstanceGroupManagersAbandonInstancesRequest(instances=[]),
project=igm_ref.project,
region=igm_ref.region,
)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='AbandonInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances)
AbandonInstances.detailed_help = {
'brief':
'Abandon instances owned by a managed instance group.',
'DESCRIPTION':
"""
*{command}* abandons one or more instances from a managed instance
group, thereby reducing the targetSize of the group. Once instances have been
abandoned, the currentSize of the group is automatically reduced as well to
reflect the change.
Abandoning an instance does not reboot or delete the underlying virtual machine
instances, but just removes the instances from the instance group. If you would
like to delete the underlying instances, use the `delete-instances` command
instead.
The command returns the operation status per instance, which might be ``FAIL'',
``SUCCESS'', or ``MEMBER_NOT_FOUND''. ``MEMBER_NOT_FOUND'' is returned only for
regional groups when the gcloud command-line tool wasn't able to resolve the
zone from the instance name.
For a more detailed overview of how abandoning instances from a managed instance
group works, see [Abandoning instances from a MIG](https://cloud.google.com/compute/docs/instance-groups/add-remove-vms-in-mig#abandoning_instances).
""",
}

View File

@@ -0,0 +1,28 @@
# -*- 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.
"""Commands for reading and manipulating managed instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class ManagedInstanceGroupsAllInstancesConfig(base.Group):
"""Override instance template settings for all instances in a managed instance group."""

View File

@@ -0,0 +1,134 @@
# -*- 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 for deleting values overridden in all-instances config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils as mig_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as managed_instance_groups_flags
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class Delete(base.DeleteCommand):
"""Delete all-instances-config of a managed instance group."""
@classmethod
def Args(cls, parser):
instance_groups_flags.GetInstanceGroupManagerArg(
region_flag=True).AddArgument(
parser, operation_type='delete the all instances configuration for')
managed_instance_groups_flags.AddFlagsForDeleteAllInstancesConfig(parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
.ResolveAsResource)(
args,
resources,
scope_lister=compute_flags.GetDefaultScopeLister(client),
)
if igm_ref.Collection() not in [
'compute.instanceGroupManagers', 'compute.regionInstanceGroupManagers'
]:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
patch_instance_group_manager = self._CreateInstanceGroupManagerPatch(
args, client)
return Delete._MakePatchRequest(client, igm_ref,
patch_instance_group_manager)
def _CreateInstanceGroupManagerPatch(self, args, client):
"""Creates IGM resource patch."""
mig_utils.RegisterCustomInstancePropertiesPatchEncoders(client)
metadata = args.metadata or []
labels = args.labels or []
return client.messages.InstanceGroupManager(
allInstancesConfig=client.messages
.InstanceGroupManagerAllInstancesConfig(
properties=client.messages.InstancePropertiesPatch(
metadata=client.messages.InstancePropertiesPatch.MetadataValue(
additionalProperties=[
client.messages.InstancePropertiesPatch.MetadataValue
.AdditionalProperty(key=key, value=None)
for key in metadata
]),
labels=client.messages.InstancePropertiesPatch.LabelsValue(
additionalProperties=[
client.messages.InstancePropertiesPatch.LabelsValue
.AdditionalProperty(key=key, value=None)
for key in labels
]))))
@staticmethod
def _MakePatchRequest(client, igm_ref, igm_updated_resource):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request = client.messages.ComputeInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_updated_resource,
project=igm_ref.project,
zone=igm_ref.zone)
else:
service = client.apitools_client.regionInstanceGroupManagers
request = client.messages.ComputeRegionInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_updated_resource,
project=igm_ref.project,
region=igm_ref.region)
return client.MakeRequests([(service, 'Patch', request)])
Delete.detailed_help = {
'brief':
'Delete values defined in the all-instances configuration of a managed '
'instance group.',
'DESCRIPTION':
"""\
*{command}* deletes one or more values defined in the all-instances
configuration of a managed instance group.
To apply a revised all-instances configuration to existing instances
in the group, use one of the following methods:
- Update instances using the `update-instances` command.
- Recreate instances using the `recreate-instances` command.
- Use the `rolling-action start-update` command.
- Use the API to set the group's `updatePolicy.type` to `PROACTIVE`.
""",
'EXAMPLES':
"""\
To delete the group's all-instances configuration in order to stop
overriding the group's instance template for a label with the key
`label-key` and metadata with the key `metadata-key` in group
`my-group`, run:
$ {command} my-group
--metadata=metadata-key
--labels=label-key
"""
}

View File

@@ -0,0 +1,125 @@
# -*- 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 for deleting values overridden in all-instances config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as managed_instance_groups_flags
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class Update(base.UpdateCommand):
"""Update all-instances-config of a managed instance group."""
@classmethod
def Args(cls, parser):
instance_groups_flags.GetInstanceGroupManagerArg(
region_flag=True).AddArgument(
parser, operation_type='update the all instances configuration for')
managed_instance_groups_flags.AddFlagsForUpdateAllInstancesConfig(parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
.ResolveAsResource)(
args,
resources,
scope_lister=compute_flags.GetDefaultScopeLister(client),
)
if igm_ref.Collection() not in [
'compute.instanceGroupManagers', 'compute.regionInstanceGroupManagers'
]:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
patch_instance_group_manager = self._CreateInstanceGroupManagerPatch(
args, client)
return self._MakePatchRequest(client, igm_ref, patch_instance_group_manager)
def _CreateInstanceGroupManagerPatch(self, args, client):
"""Creates IGM resource patch."""
return client.messages.InstanceGroupManager(
allInstancesConfig=client.messages
.InstanceGroupManagerAllInstancesConfig(
properties=client.messages.InstancePropertiesPatch(
metadata=client.messages.InstancePropertiesPatch.MetadataValue(
additionalProperties=[
client.messages.InstancePropertiesPatch.MetadataValue
.AdditionalProperty(key=key, value=value)
for key, value in args.metadata.items()
]),
labels=client.messages.InstancePropertiesPatch.LabelsValue(
additionalProperties=[
client.messages.InstancePropertiesPatch.LabelsValue
.AdditionalProperty(key=key, value=value)
for key, value in args.labels.items()
]))))
def _MakePatchRequest(self, client, igm_ref, igm_updated_resource):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request = client.messages.ComputeInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_updated_resource,
project=igm_ref.project,
zone=igm_ref.zone)
else:
service = client.apitools_client.regionInstanceGroupManagers
request = client.messages.ComputeRegionInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_updated_resource,
project=igm_ref.project,
region=igm_ref.region)
return client.MakeRequests([(service, 'Patch', request)])
Update.detailed_help = {
'brief':
'Update the all-instances configuration of a managed instance group.',
'DESCRIPTION':
"""\
*{command}* updates the group's all-instances configuration and applies
it only to new instances that are added to the group.
To apply a revised all-instances configuration to existing instances
in the group, use one of the following methods:
- Update instances using the `update-instances` command.
- Recreate instances using the `recreate-instances` command.
- Use the `rolling-action start-update` command.
- Use the API to set the group's `updatePolicy.type` to `PROACTIVE`.
""",
'EXAMPLES':
"""\
To update an all-instances configuration in order to override the
group's instance template for a label with the key `label-key`
and metadata with the key `metadata-key` in group `my-group`, run:
$ {command} my-group
--metadata=metadata-key=metadata-override-value
--labels=qlabel-key=label-override-value
"""
}

View File

@@ -0,0 +1,513 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for creating managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import sys
from apitools.base.py import encoding
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.api_lib.compute import zone_utils
from googlecloudsdk.api_lib.compute.instance_groups.managed import stateful_policy_utils as policy_utils
from googlecloudsdk.api_lib.compute.managed_instance_groups_utils import ValueOrNone
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import resource_manager_tags_utils
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as managed_flags
from googlecloudsdk.command_lib.compute.managed_instance_groups import auto_healing_utils
from googlecloudsdk.command_lib.util.apis import arg_utils
from googlecloudsdk.core import properties
import six
# API allows up to 58 characters but asked us to send only 54 (unless user
# explicitly asks us for more).
_MAX_LEN_FOR_DEDUCED_BASE_INSTANCE_NAME = 54
# Flags valid only for regional MIGs.
REGIONAL_FLAGS = [
'instance_redistribution_type',
'target_distribution_shape',
'on_repair_allow_changing_zone',
]
def _AddInstanceGroupManagerArgs(parser):
"""Adds args."""
parser.add_argument(
'--base-instance-name',
help=('Base name to use for the Compute Engine instances that will '
'be created with the managed instance group. If not provided '
'base instance name will be the prefix of instance group name.'))
parser.add_argument(
'--size',
required=True,
type=arg_parsers.BoundedInt(0, sys.maxsize, unlimited=True),
help='Initial number of instances you want in this group.')
instance_groups_flags.AddDescriptionFlag(parser)
parser.add_argument(
'--target-pool',
type=arg_parsers.ArgList(),
metavar='TARGET_POOL',
help=('Specifies any target pools you want the instances of this '
'managed instance group to be part of.'))
managed_flags.INSTANCE_TEMPLATE_ARG.AddArgument(parser)
def _IsZonalGroup(ref):
"""Checks if reference to instance group is zonal."""
return ref.Collection() == 'compute.instanceGroupManagers'
def ValidateUpdatePolicyAgainstStateful(update_policy, group_ref,
stateful_policy, client):
"""Validates and fixed update policy for stateful MIG.
Sets default values in update_policy for stateful IGMs or throws exception
if the wrong value is set explicitly.
Args:
update_policy: Update policy to be validated
group_ref: Reference of IGM being validated
stateful_policy: Stateful policy to check if the group is stateful
client: The compute API client
"""
if stateful_policy is None or _IsZonalGroup(group_ref):
return
redistribution_type_none = (
client.messages.InstanceGroupManagerUpdatePolicy
.InstanceRedistributionTypeValueValuesEnum.NONE)
if (not update_policy or
update_policy.instanceRedistributionType != redistribution_type_none):
raise exceptions.RequiredArgumentException(
'--instance-redistribution-type',
'Stateful regional IGMs need to have instance redistribution type '
'set to \'NONE\'. Use \'--instance-redistribution-type=NONE\'.')
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class CreateGA(base.CreateCommand):
"""Create Compute Engine managed instance groups."""
support_update_policy_min_ready_flag = False
support_resource_manager_tags = False
@classmethod
def Args(cls, parser):
parser.display_info.AddFormat(managed_flags.DEFAULT_CREATE_OR_LIST_FORMAT)
_AddInstanceGroupManagerArgs(parser)
auto_healing_utils.AddAutohealingArgs(parser)
igm_arg = instance_groups_flags.GetInstanceGroupManagerArg(zones_flag=True)
igm_arg.AddArgument(parser, operation_type='create')
instance_groups_flags.AddZonesFlag(parser)
instance_groups_flags.AddMigCreateStatefulFlags(parser)
instance_groups_flags.AddMigCreateStatefulIPsFlags(parser)
managed_flags.AddMigInstanceRedistributionTypeFlag(parser)
managed_flags.AddMigDistributionPolicyTargetShapeFlag(parser)
managed_flags.AddMigListManagedInstancesResultsFlag(parser)
managed_flags.AddMigUpdatePolicyFlags(
parser, support_min_ready_flag=cls.support_update_policy_min_ready_flag)
managed_flags.AddMigForceUpdateOnRepairFlags(parser)
if cls.support_resource_manager_tags:
managed_flags.AddMigResourceManagerTagsFlags(parser)
managed_flags.AddMigDefaultActionOnVmFailure(parser, cls.ReleaseTrack())
managed_flags.AddInstanceFlexibilityPolicyArgs(parser)
managed_flags.AddStandbyPolicyFlags(parser)
managed_flags.AddWorkloadPolicyFlag(parser)
# When adding RMIG-specific flag, update REGIONAL_FLAGS constant.
def _HandleStatefulArgs(self, instance_group_manager, args, client):
instance_groups_flags.ValidateManagedInstanceGroupStatefulDisksProperties(
args)
instance_groups_flags.ValidateManagedInstanceGroupStatefulIPsProperties(
args
)
if (
args.stateful_disk
or args.stateful_internal_ip
or args.stateful_external_ip
):
instance_group_manager.statefulPolicy = (
self._CreateStatefulPolicy(args, client))
def _CreateStatefulPolicy(self, args, client):
"""Create stateful policy from disks of args --stateful-disk, and ips of args --stateful-external-ips and --stateful-internal-ips."""
stateful_disks = []
for stateful_disk_dict in (args.stateful_disk or []):
stateful_disks.append(
policy_utils.MakeStatefulPolicyPreservedStateDiskEntry(
client.messages, stateful_disk_dict))
stateful_disks.sort(key=lambda x: x.key)
stateful_policy = policy_utils.MakeStatefulPolicy(
client.messages, stateful_disks
)
stateful_internal_ips = []
for stateful_ip_dict in args.stateful_internal_ip or []:
stateful_internal_ips.append(
policy_utils.MakeStatefulPolicyPreservedStateInternalIPEntry(
client.messages, stateful_ip_dict
)
)
stateful_internal_ips.sort(key=lambda x: x.key)
stateful_policy.preservedState.internalIPs = (
client.messages.StatefulPolicyPreservedState.InternalIPsValue(
additionalProperties=stateful_internal_ips
)
)
stateful_external_ips = []
for stateful_ip_dict in args.stateful_external_ip or []:
stateful_external_ips.append(
policy_utils.MakeStatefulPolicyPreservedStateExternalIPEntry(
client.messages, stateful_ip_dict
)
)
stateful_external_ips.sort(key=lambda x: x.key)
stateful_policy.preservedState.externalIPs = (
client.messages.StatefulPolicyPreservedState.ExternalIPsValue(
additionalProperties=stateful_external_ips
)
)
return stateful_policy
def _CreateGroupReference(self, args, client, resources):
if args.zones:
zone_ref = resources.Parse(
args.zones[0],
collection='compute.zones',
params={'project': properties.VALUES.core.project.GetOrFail})
region = utils.ZoneNameToRegionName(zone_ref.Name())
return resources.Parse(
args.name,
params={
'region': region,
'project': properties.VALUES.core.project.GetOrFail
},
collection='compute.regionInstanceGroupManagers')
group_ref = (
instance_groups_flags.GetInstanceGroupManagerArg().ResolveAsResource)(
args,
resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client))
if _IsZonalGroup(group_ref):
zonal_resource_fetcher = zone_utils.ZoneResourceFetcher(client)
zonal_resource_fetcher.WarnForZonalCreation([group_ref])
return group_ref
def _CreateDistributionPolicy(self, args, resources, messages):
distribution_policy = messages.DistributionPolicy()
if args.zones:
policy_zones = []
for zone in args.zones:
zone_ref = resources.Parse(
zone,
collection='compute.zones',
params={'project': properties.VALUES.core.project.GetOrFail})
policy_zones.append(
messages.DistributionPolicyZoneConfiguration(
zone=zone_ref.SelfLink()))
distribution_policy.zones = policy_zones
if args.target_distribution_shape:
distribution_policy.targetShape = arg_utils.ChoiceToEnum(
args.target_distribution_shape,
messages.DistributionPolicy.TargetShapeValueValuesEnum)
return ValueOrNone(distribution_policy)
def _GetRegionForGroup(self, group_ref):
if _IsZonalGroup(group_ref):
return utils.ZoneNameToRegionName(group_ref.zone)
else:
return group_ref.region
def _GetServiceForGroup(self, group_ref, compute):
if _IsZonalGroup(group_ref):
return compute.instanceGroupManagers
else:
return compute.regionInstanceGroupManagers
def _CreateResourceRequest(self, group_ref, instance_group_manager, client,
resources):
if _IsZonalGroup(group_ref):
instance_group_manager.zone = group_ref.zone
return client.messages.ComputeInstanceGroupManagersInsertRequest(
instanceGroupManager=instance_group_manager,
project=group_ref.project,
zone=group_ref.zone)
else:
region_link = resources.Parse(
group_ref.region,
params={'project': properties.VALUES.core.project.GetOrFail},
collection='compute.regions')
instance_group_manager.region = region_link.SelfLink()
return client.messages.ComputeRegionInstanceGroupManagersInsertRequest(
instanceGroupManager=instance_group_manager,
project=group_ref.project,
region=group_ref.region)
def _GetInstanceGroupManagerTargetPools(self, target_pools, group_ref,
holder):
pool_refs = []
if target_pools:
region = self._GetRegionForGroup(group_ref)
for pool in target_pools:
pool_refs.append(
holder.resources.Parse(
pool,
params={
'project': properties.VALUES.core.project.GetOrFail,
'region': region
},
collection='compute.targetPools'))
return [pool_ref.SelfLink() for pool_ref in pool_refs]
def _CreateParams(self, client, resource_manager_tags):
resource_manager_tags_map = (
resource_manager_tags_utils.GetResourceManagerTags(
resource_manager_tags
)
)
params = client.messages.InstanceGroupManagerParams
additional_properties = [
params.ResourceManagerTagsValue.AdditionalProperty(key=key, value=value)
for key, value in sorted(six.iteritems(resource_manager_tags_map))
]
return params(
resourceManagerTags=params.ResourceManagerTagsValue(
additionalProperties=additional_properties
)
)
def _CreateInstanceGroupManager(self, args, group_ref, template_ref, client,
holder):
"""Create parts of Instance Group Manager shared for the track."""
managed_flags.ValidateRegionalMigFlagsUsage(args, REGIONAL_FLAGS, group_ref)
instance_groups_flags.ValidateManagedInstanceGroupScopeArgs(
args, holder.resources)
health_check = managed_instance_groups_utils.GetHealthCheckUri(
holder.resources, args)
auto_healing_policies = (
managed_instance_groups_utils.CreateAutohealingPolicies(
client.messages, health_check, args.initial_delay))
managed_instance_groups_utils.ValidateAutohealingPolicies(
auto_healing_policies)
update_policy = managed_instance_groups_utils.PatchUpdatePolicy(
client, args, None)
instance_lifecycle_policy = (
managed_instance_groups_utils.CreateInstanceLifecyclePolicy(
client.messages, args
)
)
instance_flexibility_policy = (
managed_instance_groups_utils.CreateInstanceFlexibilityPolicy(
args, client.messages
)
)
resource_policies = managed_instance_groups_utils.CreateResourcePolicies(
client.messages, args
)
instance_group_manager = client.messages.InstanceGroupManager(
name=group_ref.Name(),
description=args.description,
instanceTemplate=template_ref.SelfLink(),
baseInstanceName=args.base_instance_name,
targetPools=self._GetInstanceGroupManagerTargetPools(
args.target_pool, group_ref, holder
),
targetSize=int(args.size),
autoHealingPolicies=auto_healing_policies,
distributionPolicy=self._CreateDistributionPolicy(
args, holder.resources, client.messages
),
updatePolicy=update_policy,
instanceLifecyclePolicy=instance_lifecycle_policy,
instanceFlexibilityPolicy=instance_flexibility_policy,
resourcePolicies=resource_policies,
)
if args.IsSpecified('list_managed_instances_results'):
instance_group_manager.listManagedInstancesResults = (
client.messages.InstanceGroupManager
.ListManagedInstancesResultsValueValuesEnum)(
args.list_managed_instances_results.upper())
if self.support_resource_manager_tags and args.resource_manager_tags:
instance_group_manager.params = self._CreateParams(
client, args.resource_manager_tags
)
self._HandleStatefulArgs(instance_group_manager, args, client)
# Validate updatePolicy + statefulPolicy combination
ValidateUpdatePolicyAgainstStateful(instance_group_manager.updatePolicy,
group_ref,
instance_group_manager.statefulPolicy,
client)
standby_policy = managed_instance_groups_utils.CreateStandbyPolicy(
client.messages,
args.standby_policy_initial_delay,
args.standby_policy_mode,
)
if standby_policy:
instance_group_manager.standbyPolicy = standby_policy
if args.suspended_size:
instance_group_manager.targetSuspendedSize = args.suspended_size
if args.stopped_size:
instance_group_manager.targetStoppedSize = args.stopped_size
if args.IsKnownAndSpecified('target_size_policy_mode'):
instance_group_manager.targetSizePolicy = (
managed_instance_groups_utils.CreateTargetSizePolicy(
client.messages, args.target_size_policy_mode
)
)
return instance_group_manager
def _PostProcessOutput(self, holder, migs):
# 0 to 1 MIGs.
for mig in [encoding.MessageToDict(m) for m in migs]:
# At this point we're missing information about autoscaler and current
# size. To avoid making additional calls to API, we assume current size to
# be 0, since MIG has just been created. We also assume that there's no
# autoscaler, since API doesn't allow to insert MIG simultaneously with
# autoscaler.
mig['size'] = 0
# Same as "mig['autoscaled'] = 'no'", but making sure that property value
# is consistent with the one used to list groups.
managed_instance_groups_utils.ResolveAutoscalingStatusForMig(
holder.client, mig)
yield mig
def Run(self, args):
"""Creates and issues an instanceGroupManagers.Insert request.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
List containing one dictionary: resource augmented with 'autoscaled'
property
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = self._CreateGroupReference(args, client, holder.resources)
template_ref = managed_flags.INSTANCE_TEMPLATE_ARG.ResolveAsResource(
args,
holder.resources,
default_scope=flags.compute_scope.ScopeEnum.GLOBAL,
)
instance_group_manager = self._CreateInstanceGroupManager(
args, group_ref, template_ref, client, holder)
request = self._CreateResourceRequest(group_ref, instance_group_manager,
client, holder.resources)
service = self._GetServiceForGroup(group_ref, client.apitools_client)
migs = client.MakeRequests([(service, 'Insert', request)])
return self._PostProcessOutput(holder, migs)
CreateGA.detailed_help = {
'brief': 'Create a Compute Engine managed instance group',
'DESCRIPTION': """\
*{command}* creates a Compute Engine managed instance group.
""",
'EXAMPLES': """\
Running:
$ {command} example-managed-instance-group --zone=us-central1-a --template=example-global-instance-template --size=1
will create a managed instance group called 'example-managed-instance-group'
in the ``us-central1-a'' zone with a global instance template resource
'example-global-instance-template'.
To use a regional instance template, specify the full or partial URL of the template.
Running:
$ {command} example-managed-instance-group --zone=us-central1-a \\
--template=projects/example-project/regions/us-central1/instanceTemplates/example-regional-instance-template \\
--size=1
will create a managed instance group called
'example-managed-instance-group' in the ``us-central1-a'' zone with a
regional instance template resource 'example-regional-instance-template'.
""",
}
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CreateBeta(CreateGA):
"""Create Compute Engine managed instance groups."""
support_update_policy_min_ready_flag = True
support_resource_manager_tags = True
@classmethod
def Args(cls, parser):
managed_flags.AddMigActionOnVmFailedHealthCheck(parser)
managed_flags.AddTargetSizePolicyModeFlag(parser)
managed_flags.AddOnRepairFlags(parser)
super(CreateBeta, cls).Args(parser)
def _CreateInstanceGroupManager(self, args, group_ref, template_ref, client,
holder):
instance_group_manager = super(CreateBeta,
self)._CreateInstanceGroupManager(
args, group_ref, template_ref, client,
holder)
return instance_group_manager
CreateBeta.detailed_help = CreateGA.detailed_help
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CreateAlpha(CreateBeta):
"""Create Compute Engine managed instance groups."""
support_resource_manager_tags = True
@classmethod
def Args(cls, parser):
super(CreateAlpha, cls).Args(parser)
def _CreateInstanceGroupManager(
self, args, group_ref, template_ref, client, holder
):
instance_group_manager = super(
CreateAlpha, self
)._CreateInstanceGroupManager(args, group_ref, template_ref, client, holder)
return instance_group_manager
CreateAlpha.detailed_help = CreateGA.detailed_help

View File

@@ -0,0 +1,174 @@
# -*- 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 for creating instance with per instance config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute.operations import poller
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed.instance_configs import instance_configs_messages
@base.ReleaseTracks(base.ReleaseTrack.GA)
class CreateInstanceGA(base.CreateCommand):
"""Create a new virtual machine instance in a managed instance group."""
@classmethod
def Args(cls, parser):
instance_groups_flags.GetInstanceGroupManagerArg(
region_flag=True).AddArgument(
parser, operation_type='create instance in')
instance_groups_flags.AddCreateInstancesFlags(parser)
@staticmethod
def _CreateNewInstanceReference(holder, igm_ref, instance_name):
"""Creates reference to instance in instance group (zonal or regional)."""
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instance_ref = holder.resources.Parse(
instance_name,
params={
'project': igm_ref.project,
'zone': igm_ref.zone,
},
collection='compute.instances')
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instance_ref = holder.resources.Parse(
instance_name,
params={
'project': igm_ref.project,
'zone': igm_ref.region + '-a',
},
collection='compute.instances')
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
if not instance_ref:
raise managed_instance_groups_utils.ResourceCannotBeResolvedException(
'Instance name {0} cannot be resolved.'.format(instance_name))
return instance_ref
def Run(self, args):
self._ValidateStatefulFlagsForInstanceConfigs(args)
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
.ResolveAsResource)(
args,
resources,
scope_lister=compute_flags.GetDefaultScopeLister(client))
instance_ref = self._CreateNewInstanceReference(
holder=holder, igm_ref=igm_ref, instance_name=args.instance)
per_instance_config_message = self._CreatePerInstanceConfgMessage(
holder, instance_ref, args)
operation_ref, service = instance_configs_messages.CallCreateInstances(
holder=holder,
igm_ref=igm_ref,
per_instance_config_message=per_instance_config_message)
operation_poller = poller.Poller(service)
create_result = waiter.WaitFor(operation_poller, operation_ref,
'Creating instance.')
return create_result
def _ValidateStatefulFlagsForInstanceConfigs(self, args):
instance_groups_flags.ValidateMigStatefulFlagsForInstanceConfigs(
args, need_disk_source=True)
instance_groups_flags.ValidateMigStatefulIPFlagsForInstanceConfigs(
args, current_internal_addresses=[], current_external_addresses=[]
)
def _CreatePerInstanceConfgMessage(self, holder, instance_ref, args):
return instance_configs_messages.CreatePerInstanceConfigMessageWithIPs(
holder,
instance_ref,
args.stateful_disk,
args.stateful_metadata,
args.stateful_internal_ip,
args.stateful_external_ip,
disk_getter=NonExistentDiskGetter(),
)
CreateInstanceGA.detailed_help = {
'brief': (
'Create a new virtual machine instance in a managed instance group '
'with a defined name and optionally its stateful configuration.'
),
'DESCRIPTION': """\
*{command}* creates a virtual machine instance with a defined name and
optionally its stateful configuration: stateful disk, stateful
metadata key-values, and stateful IP addresses. Stateful configuration
is stored in the corresponding newly created per-instance config.
An instance with a per-instance config will preserve its given name,
specified disks, specified metadata key-values, and specified internal
and external IPs during instance recreation, auto-healing, updates,
and any other lifecycle transitions of the instance.
""",
'EXAMPLES': """\
To create an instance `instance-1` in `my-group`
(in region europe-west4) with metadata `my-key: my-value`, a disk
`disk-1` attached to it as the device `device-1`,
stateful internal IP `192.168.0.10` on the default interface (nic0),
and existing address reservation `my-address` for stateful external IP
on interface `nic1`, run:
$ {command} \\
my-group --region=europe-west4 \\
--instance=instance-1 \\
--stateful-disk='device-name=foo,source=https://compute.googleapis.com/compute/alpha/projects/my-project/zones/europe-west4/disks/disk-1,mode=rw,auto-delete=on-permanent-instance-deletion' \\
--stateful-metadata='my-key=my-value' \\
--stateful-internal-ip=address=192.168.0.10,auto-delete=on-permanent-instance-deletion \\
--stateful-external-ip=address=/projects/example-project/regions/europe-west4/addresses/my-address,interface-name=nic1
""",
}
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CreateInstanceBeta(CreateInstanceGA):
"""Create a new virtual machine instance in a managed instance group."""
CreateInstanceBeta.detailed_help = CreateInstanceGA.detailed_help
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CreateInstanceAlpha(CreateInstanceBeta):
"""Create a new virtual machine instance in a managed instance group."""
CreateInstanceAlpha.detailed_help = CreateInstanceBeta.detailed_help
class NonExistentDiskGetter(object):
"""Placeholder class returning None."""
def __init__(self):
self.instance_exists = False
def get_disk(self, device_name): # pylint: disable=unused-argument,g-bad-name
return

View File

@@ -0,0 +1,191 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for deleting managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute import path_simplifier
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.core import properties
from googlecloudsdk.core.console import progress_tracker
from googlecloudsdk.core.util import text
from six.moves import zip
# During delete, graceful shutdown can take up to 60 minutes to complete, we
# are setting timeout to `70` minutes to give some space for delete operation
# to complete gracefully
_TIMEOUT_IN_SEC = 60 * 70
@base.UniverseCompatible
class Delete(base.DeleteCommand):
"""Delete Compute Engine managed instance group."""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGERS_ARG.AddArgument(
parser, operation_type='delete')
def _GenerateAutoscalerDeleteRequests(self, holder, project, mig_requests):
"""Generates Delete requestes for autoscalers attached to instance groups.
Args:
holder: ComputeApiHolder, object encapsulating compute api.
project: str, project this request should apply to.
mig_requests: Messages which will be sent to delete instance group
managers.
Returns:
Messages, which will be sent to delete autoscalers.
"""
mig_requests = list(zip(*mig_requests))[2] if mig_requests else []
zone_migs = [(request.instanceGroupManager, 'zone',
managed_instance_groups_utils.CreateZoneRef(
holder.resources, request)) for request in mig_requests
if hasattr(request, 'zone') and request.zone is not None]
region_migs = [(request.instanceGroupManager, 'region',
managed_instance_groups_utils.CreateRegionRef(
holder.resources, request)) for request in mig_requests
if hasattr(request, 'region') and request.region is not None]
zones = list(zip(*zone_migs))[2] if zone_migs else []
regions = list(zip(*region_migs))[2] if region_migs else []
client = holder.client.apitools_client
messages = client.MESSAGES_MODULE
autoscalers_to_delete = managed_instance_groups_utils.AutoscalersForMigs(
migs=zone_migs + region_migs,
autoscalers=managed_instance_groups_utils.AutoscalersForLocations(
zones=zones,
regions=regions,
client=holder.client))
requests = []
for autoscaler in autoscalers_to_delete:
if autoscaler.zone:
service = client.autoscalers
request = messages.ComputeAutoscalersDeleteRequest(
zone=path_simplifier.Name(autoscaler.zone))
else:
service = client.regionAutoscalers
request = messages.ComputeRegionAutoscalersDeleteRequest(
region=path_simplifier.Name(autoscaler.region))
request.autoscaler = autoscaler.name
request.project = project
requests.append((service, 'Delete', request))
return requests
def _GetCommonScopeNameForRefs(self, refs):
"""Gets common scope for references."""
has_zone = any(hasattr(ref, 'zone') for ref in refs)
has_region = any(hasattr(ref, 'region') for ref in refs)
if has_zone and not has_region:
return 'zone'
elif has_region and not has_zone:
return 'region'
else:
return None
def _CreateDeleteRequests(self, client, igm_refs):
"""Returns a list of delete messages for instance group managers."""
messages = client.MESSAGES_MODULE
requests = []
for ref in igm_refs:
if ref.Collection() == 'compute.instanceGroupManagers':
service = client.instanceGroupManagers
request = messages.ComputeInstanceGroupManagersDeleteRequest(
instanceGroupManager=ref.Name(),
project=ref.project,
zone=ref.zone)
elif ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.regionInstanceGroupManagers
request = messages.ComputeRegionInstanceGroupManagersDeleteRequest(
instanceGroupManager=ref.Name(),
project=ref.project,
region=ref.region)
else:
raise ValueError('Unknown reference type {0}'.format(ref.Collection()))
requests.append((service, 'Delete', request))
return requests
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
project = properties.VALUES.core.project.Get(required=True)
igm_refs = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGERS_ARG.
ResolveAsResource)(
args, holder.resources, default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(holder.client, project))
scope_name = self._GetCommonScopeNameForRefs(igm_refs)
utils.PromptForDeletion(
igm_refs, scope_name=scope_name, prompt_title=None)
requests = list(self._CreateDeleteRequests(
holder.client.apitools_client, igm_refs))
resources = []
# Delete autoscalers first.
errors = []
autoscaler_delete_requests = self._GenerateAutoscalerDeleteRequests(
holder, project, mig_requests=requests)
if autoscaler_delete_requests:
with progress_tracker.ProgressTracker(
'Deleting ' + text.Pluralize(
len(autoscaler_delete_requests), 'autoscaler'),
autotick=False,
) as tracker:
resources = holder.client.MakeRequests(
autoscaler_delete_requests,
errors,
progress_tracker=tracker)
if errors:
utils.RaiseToolException(errors)
# Now delete instance group managers.
errors = []
with progress_tracker.ProgressTracker(
'Deleting ' + text.Pluralize(len(requests), 'Managed Instance Group'),
autotick=False,
) as tracker:
resources += holder.client.MakeRequests(
requests, errors, progress_tracker=tracker, timeout=_TIMEOUT_IN_SEC
)
if errors:
utils.RaiseToolException(errors)
return resources
Delete.detailed_help = {
'brief': 'Delete Compute Engine managed instance groups',
'DESCRIPTION': """\
*{command}* deletes one or more Compute Engine managed instance
groups.
""",
}

View File

@@ -0,0 +1,151 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for deleting instances managed by managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as mig_flags
def _AddCommonDeleteInstancesArgs(parser):
"""Add parser configuration common for all release tracks."""
parser.display_info.AddFormat(
mig_flags.GetCommonPerInstanceCommandOutputFormat())
parser.add_argument(
'--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
required=True,
help='Names of instances to delete.')
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
mig_flags.AddGracefulValidationArg(parser)
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
@base.UniverseCompatible
class DeleteInstances(base.Command):
"""Delete instances managed by managed instance group."""
@staticmethod
def Args(parser):
_AddCommonDeleteInstancesArgs(parser)
def Run(self, args):
self._UpdateDefaultOutputFormatForGracefulValidation(args)
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instances_holder_field = 'instanceGroupManagersDeleteInstancesRequest'
request = self._CreateZonalIgmDeleteInstancesRequest(
client.messages, igm_ref, args)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instances_holder_field = 'regionInstanceGroupManagersDeleteInstancesRequest'
request = self._CreateRegionalIgmDeleteInstancesRequest(
client.messages, igm_ref, args)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
skip_instances_on_validation_error = (
args.IsSpecified('skip_instances_on_validation_error')
and args.skip_instances_on_validation_error
)
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='DeleteInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances,
per_instance_status_enabled=True,
skip_instances_on_validation_error=skip_instances_on_validation_error)
def _CreateZonalIgmDeleteInstancesRequest(self, messages, igm_ref, args):
request = messages.ComputeInstanceGroupManagersDeleteInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersDeleteInstancesRequest=messages
.InstanceGroupManagersDeleteInstancesRequest(instances=[]),
project=igm_ref.project,
zone=igm_ref.zone)
if args.IsSpecified('skip_instances_on_validation_error'):
(request.instanceGroupManagersDeleteInstancesRequest.
skipInstancesOnValidationError) = args.skip_instances_on_validation_error
return request
def _CreateRegionalIgmDeleteInstancesRequest(self, messages, igm_ref, args):
request = messages.ComputeRegionInstanceGroupManagersDeleteInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersDeleteInstancesRequest=messages
.RegionInstanceGroupManagersDeleteInstancesRequest(instances=[]),
project=igm_ref.project,
region=igm_ref.region)
if args.IsSpecified('skip_instances_on_validation_error'):
(request.regionInstanceGroupManagersDeleteInstancesRequest.
skipInstancesOnValidationError) = args.skip_instances_on_validation_error
return request
def _UpdateDefaultOutputFormatForGracefulValidation(self, args):
# Do not override output format if specified by user.
if args.IsSpecified('format'):
return
# Add VALIDATION_ERROR column if graceful validation is enabled.
if args.skip_instances_on_validation_error:
args.format = mig_flags.GetCommonPerInstanceCommandOutputFormat(
with_validation_error=True)
DeleteInstances.detailed_help = {
'brief':
'Delete instances that are managed by a managed instance group.',
'DESCRIPTION':
"""
*{command}* is used to delete one or more instances from a managed
instance group. Once the instances are deleted, the size of the group is
automatically reduced to reflect the changes.
The command returns the operation status per instance, which might be ``FAIL'',
``SUCCESS'', ``SKIPPED'', or ``MEMBER_NOT_FOUND''. ``MEMBER_NOT_FOUND'' is
returned only for regional groups when the gcloud command-line tool wasn't able
to resolve the zone from the instance name. ``SKIPPED'' is returned only when
the `--skip-instances-on-validation-error` flag is used and the instance is not
a member of the group or is already being deleted or abandoned.
If you want to keep the underlying virtual machines but still remove them
from the managed instance group, use the abandon-instances command instead.
""",
}

View File

@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for describing managed instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import encoding
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags
class Describe(base.DescribeCommand):
"""Display detailed information about a managed instance group."""
@staticmethod
def Args(parser):
flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser, operation_type='describe')
def Collection(self):
return 'compute.instanceGroupManagers'
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
apitools_client = client.apitools_client
messages = client.messages
resources = holder.resources
ref = flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.ResolveAsResource(
args, resources,
scope_lister=compute_flags.GetDefaultScopeLister(client))
if ref.Collection() == 'compute.instanceGroupManagers':
service = apitools_client.instanceGroupManagers
request_type = messages.ComputeInstanceGroupManagersGetRequest
elif ref.Collection() == 'compute.regionInstanceGroupManagers':
service = apitools_client.regionInstanceGroupManagers
request_type = messages.ComputeRegionInstanceGroupManagersGetRequest
else:
raise ValueError('Unknown reference type {0}'.format(ref.Collection()))
igm = encoding.MessageToDict(service.Get(request_type(**ref.AsDict())))
annoted_igm = managed_instance_groups_utils.AddAutoscalersToMigs(
migs_iterator=[igm],
client=client,
resources=resources,
fail_when_api_not_supported=False)
return list(annoted_igm)[0]
Describe.detailed_help = base_classes.GetMultiScopeDescriberHelp(
'instance group', (base_classes.ScopeType.regional_scope,
base_classes.ScopeType.zonal_scope))

View File

@@ -0,0 +1,117 @@
# -*- 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 for creating instance with per instance config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import encoding
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import request_helper
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class DescribeInstance(base.DescribeCommand):
"""Describe an instance in a managed instance group."""
@staticmethod
def Args(parser):
instance_groups_flags.GetInstanceGroupManagerArg(
region_flag=True).AddArgument(
parser, operation_type='describe an instance in')
parser.add_argument(
'--instance',
required=True,
help='Name of the managed instance to describe.')
def Run(self, args):
"""Retrieves response with instance in the instance group."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
group_ref = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
.ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=compute_flags.GetDefaultScopeLister(client)))
if hasattr(group_ref, 'zone'):
service = client.apitools_client.instanceGroupManagers
request = (
client.messages
.ComputeInstanceGroupManagersListManagedInstancesRequest(
instanceGroupManager=group_ref.Name(),
zone=group_ref.zone,
project=group_ref.project))
elif hasattr(group_ref, 'region'):
service = client.apitools_client.regionInstanceGroupManagers
request = (
client.messages
.ComputeRegionInstanceGroupManagersListManagedInstancesRequest(
instanceGroupManager=group_ref.Name(),
region=group_ref.region,
project=group_ref.project))
errors = []
results = list(
request_helper.MakeRequests(
requests=[(service, 'ListManagedInstances', request)],
http=client.apitools_client.http,
batch_url=client.batch_url,
errors=errors))
if errors:
utils.RaiseToolException(errors)
instance_with_name = next(
(instance for instance in results
if resources.ParseURL(instance.instance).Name() == args.instance),
None)
if not instance_with_name:
raise ValueError('Unknown instance with name `{0}\''.format(args.name))
# Add name to instance and return it
instance_with_name = encoding.MessageToDict(instance_with_name)
instance_with_name['name'] = (
resources.ParseURL(instance_with_name['instance']).Name())
return instance_with_name
DescribeInstance.detailed_help = {
'brief':
'Describe an instance in a managed instance group.',
'DESCRIPTION':
"""\
*{command}* describes an instance in a managed instance group, listing
all its attributes in YAML format.
""",
'EXAMPLES':
"""\
To describe an instance `instance-1` in `my-group`
(in region europe-west4), run:
$ {command} \\
my-group --instance=instance-1 \\
--region=europe-west4
"""
}

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for configuring autoscaling of a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import json
from apitools.base.py import encoding
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.core.util import files
_IGNORED_FIELDS = ['creationTimestamp', 'id', 'kind', 'name', 'region',
'selfLink', 'status', 'statusDetails', 'target', 'zone']
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class ExportAutoscaling(base.Command):
"""Export autoscaling parameters of a managed instance group to JSON."""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
parser.add_argument(
'--autoscaling-file',
metavar='PATH',
required=True,
help=('Path of the file to which autoscaling configuration will be '
'written.'))
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = instance_groups_flags.CreateGroupReference(
client, holder.resources, args)
autoscaler = managed_instance_groups_utils.AutoscalerForMigByRef(
client, holder.resources, igm_ref)
if autoscaler:
autoscaler_dict = encoding.MessageToDict(autoscaler)
for f in _IGNORED_FIELDS:
if f in autoscaler_dict:
del autoscaler_dict[f]
else:
autoscaler_dict = None
files.WriteFileContents(args.autoscaling_file, json.dumps(autoscaler_dict))
ExportAutoscaling.detailed_help = {
'brief': 'Export autoscaling parameters of a managed instance group',
'DESCRIPTION': """
*{command}* exports the autoscaling parameters of the specified managed
instance group.
Autoscalers can use one or more autoscaling signals. Information on using
multiple autoscaling signals can be found here: [](https://cloud.google.com/compute/docs/autoscaler/multiple-signals)
""",
}

View File

@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for listing named ports in instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.core import properties
class GetNamedPorts(base.ListCommand):
"""Implements get-named-ports command, alpha, and beta versions."""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.AddArgument(parser)
parser.display_info.AddFormat('table(name, port)')
def Run(self, args):
"""Retrieves response with named ports."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
project = properties.VALUES.core.project.Get(required=True)
group_ref = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(
holder.client, project)))
return instance_groups_utils.OutputNamedPortsForGroup(
group_ref, holder.client)
detailed_help = (
instance_groups_utils.INSTANCE_GROUP_GET_NAMED_PORT_DETAILED_HELP)

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 reading and manipulating managed instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class ManagedInstanceGroupsInstanceConfigs(base.Group):
"""Manage instance-specific settings in a managed instance group."""

View File

@@ -0,0 +1,210 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for creating per-instance config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute.operations import poller
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed.instance_configs import instance_configs_getter
from googlecloudsdk.command_lib.compute.instance_groups.managed.instance_configs import instance_configs_messages
import six
# TODO(b/70321546): rewrite help
@base.ReleaseTracks(base.ReleaseTrack.GA)
class CreateGA(base.CreateCommand):
"""Create per-instance config for an instance in a managed instance group."""
@classmethod
def Args(cls, parser):
instance_groups_flags.GetInstanceGroupManagerArg(
region_flag=True).AddArgument(
parser, operation_type='create a per-instance config for')
instance_groups_flags.AddMigStatefulFlagsForInstanceConfigs(parser)
instance_groups_flags.AddMigStatefulUpdateInstanceFlag(parser)
instance_groups_flags.AddMigStatefulIPsFlagsForInstanceConfigs(parser)
@staticmethod
def _CreateInstanceReference(holder, igm_ref, instance_name):
"""Creates reference to instance in instance group (zonal or regional)."""
if instance_name.startswith('https://') or instance_name.startswith(
'http://'):
return holder.resources.ParseURL(instance_name)
instance_references = (
managed_instance_groups_utils.CreateInstanceReferences)(
holder=holder, igm_ref=igm_ref, instance_names=[instance_name])
if not instance_references:
raise managed_instance_groups_utils.ResourceCannotBeResolvedException(
'Instance name {0} cannot be resolved'.format(instance_name))
return instance_references[0]
def Run(self, args):
self._ValidateStatefulFlagsForInstanceConfigs(args)
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.
ResolveAsResource)(
args,
resources,
scope_lister=compute_flags.GetDefaultScopeLister(client),
)
instance_ref = self._CreateInstanceReference(
holder=holder, igm_ref=igm_ref, instance_name=args.instance)
configs_getter = (
instance_configs_getter.InstanceConfigsGetterWithSimpleCache)(
client)
configs_getter.check_if_instance_config_exists(
igm_ref=igm_ref, instance_ref=instance_ref, should_exist=False)
per_instance_config_message = self._CreatePerInstanceConfigMessage(
holder, instance_ref, args)
operation_ref = instance_configs_messages.CallPerInstanceConfigUpdate(
holder=holder,
igm_ref=igm_ref,
per_instance_config_message=per_instance_config_message)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.apitools_client.regionInstanceGroupManagers
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
operation_poller = poller.Poller(service)
create_result = waiter.WaitFor(operation_poller, operation_ref,
'Creating instance config.')
if args.update_instance:
apply_operation_ref = (
instance_configs_messages.CallApplyUpdatesToInstances)(
holder=holder,
igm_ref=igm_ref,
instances=[six.text_type(instance_ref)],
minimal_action=args.instance_update_minimal_action)
return waiter.WaitFor(operation_poller, apply_operation_ref,
'Applying updates to instances.')
return create_result
def _ValidateStatefulFlagsForInstanceConfigs(self, args):
instance_groups_flags.ValidateMigStatefulFlagsForInstanceConfigs(args)
instance_groups_flags.ValidateMigStatefulIPFlagsForInstanceConfigs(
args=args, current_internal_addresses=[], current_external_addresses=[])
def _CreatePerInstanceConfigMessage(self, holder, instance_ref, args):
return instance_configs_messages.CreatePerInstanceConfigMessageWithIPs(
holder,
instance_ref,
args.stateful_disk,
args.stateful_metadata,
args.stateful_internal_ip,
args.stateful_external_ip,
)
CreateGA.detailed_help = {
'brief': (
'Create a per-instance config for an instance in a '
'managed instance group.'
),
'DESCRIPTION': """\
*{command}* creates a per-instance config for an instance controlled by
a Compute Engine managed instance group. An instance with a per-instance
config preserves the specified metadata and/or disks during
instance recreation and deletion.
Once created, the config is applied immediately to the corresponding
instance, by performing the necessary action (for example, REFRESH),
unless overridden by providing the ``--no-update-instance'' flag.
""",
'EXAMPLES': """\
To create a per-instance config with a stateful disk ``my-disk'' and to
add stateful metadata ``my-key:my-value'', on instance
``my-instance'', run:
$ {{command}} {group} {region} {instance} {disk} {metadata}
If ``my-disk'' did not exist previously in the per-instance config,
and if it does not exist in the group's instance template, then the
command adds ``my-disk'' to my-instance.
To create a per-instance config with a stateful internal IP
``192.168.0.10'' and a stateful external IP reserved in address
``my-address'', on instance ``my-instance'', run:
$ {{command}} {group} {region} {instance} {internal_ip} {external_ip}
If the provided IP address is not yet reserved, the MIG automatically
creates a corresponding IP address reservation.
""".format(
group='my-group',
region='--region=europe-west4',
instance='--instance=my-instance',
disk=(
'--stateful-disk=device-name=my-disk,source='
'projects/my-project/zones/us-central1-a/disks/my-disk-3'
),
metadata='--stateful-metadata="my-key=my-value"',
internal_ip=(
'--stateful-internal-ip=address=192.168.0.10,interface-name=nic0'
),
external_ip=(
'--stateful-external-ip=address='
'/projects/example-project/regions/europe-west4/'
'addresses/my-address'
',interface-name=nic0'
),
),
}
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CreateBeta(CreateGA):
"""Create per-instance config for an instance in a managed instance group."""
@classmethod
def Args(cls, parser):
CreateGA.Args(parser)
CreateBeta.detailed_help = CreateGA.detailed_help
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CreateAlpha(CreateBeta):
"""Create per-instance config for an instance in a managed instance group."""
@classmethod
def Args(cls, parser):
CreateBeta.Args(parser)
CreateAlpha.detailed_help = CreateBeta.detailed_help

View File

@@ -0,0 +1,160 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for deleting managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute.operations import poller
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed.instance_configs import instance_configs_messages
from googlecloudsdk.core import properties
from six.moves import map
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class Delete(base.DeleteCommand):
"""Delete per-instance configs from managed instance group."""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser, operation_type='delete')
instance_groups_flags.AddMigStatefulUpdateInstanceFlag(parser)
parser.add_argument(
'--instances',
metavar='INSTANCE',
required=True,
type=arg_parsers.ArgList(min_length=1),
help='Names of instances to delete instance-configs from.')
@staticmethod
def _GetInstanceNameListFromUrlList(holder, instances):
instance_names = [
holder.resources.ParseURL(instance).Name() for instance in instances
]
return instance_names
@staticmethod
def _GetDeletePerInstanceConfigRequests(holder, igm_ref, instances):
"""Returns a delete message for instance group manager."""
messages = holder.client.messages
req = messages.InstanceGroupManagersDeletePerInstanceConfigsReq(
names=Delete._GetInstanceNameListFromUrlList(holder, instances))
return messages.ComputeInstanceGroupManagersDeletePerInstanceConfigsRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersDeletePerInstanceConfigsReq=req,
project=igm_ref.project,
zone=igm_ref.zone,
)
@staticmethod
def _GetRegionDeletePerInstanceConfigRequests(holder, igm_ref, instances):
"""Returns a delete message for regional instance group manager."""
messages = holder.client.messages
req = messages.RegionInstanceGroupManagerDeleteInstanceConfigReq(
names=Delete._GetInstanceNameListFromUrlList(holder, instances))
return (messages.
ComputeRegionInstanceGroupManagersDeletePerInstanceConfigsRequest)(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagerDeleteInstanceConfigReq=req,
project=igm_ref.project,
region=igm_ref.region,
)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
project = properties.VALUES.core.project.Get(required=True)
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.
ResolveAsResource)(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(
holder.client, project))
instances = list(map(str,
managed_instance_groups_utils.CreateInstanceReferences(
holder, igm_ref, args.instances)))
if igm_ref.Collection() == 'compute.instanceGroupManagers':
operation_collection = 'compute.zoneOperations'
service = holder.client.apitools_client.instanceGroupManagers
delete_request = self._GetDeletePerInstanceConfigRequests(
holder, igm_ref, instances)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
operation_collection = 'compute.regionOperations'
service = holder.client.apitools_client.regionInstanceGroupManagers
delete_request = self._GetRegionDeletePerInstanceConfigRequests(
holder, igm_ref, instances)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
operation = service.DeletePerInstanceConfigs(delete_request)
operation_ref = holder.resources.Parse(
operation.selfLink, collection=operation_collection)
operation_poller = poller.Poller(service)
delete_result = waiter.WaitFor(operation_poller, operation_ref,
'Deleting instance configs.')
if args.update_instance:
apply_operation_ref = (
instance_configs_messages.CallApplyUpdatesToInstances)(
holder=holder,
igm_ref=igm_ref,
instances=instances,
minimal_action=args.instance_update_minimal_action)
return waiter.WaitFor(operation_poller, apply_operation_ref,
'Applying updates to instances.')
return delete_result
Delete.detailed_help = {
'brief':
'Delete per-instance configs from a managed instance group.',
'DESCRIPTION':
"""\
*{command}* deletes one or more per-instance configs from a Google
Compute Engine managed instance group.
Changes are applied immediately to the corresponding instances, by
performing the necessary action (for example, REFRESH), unless
overridden by providing the ``--no-update-instance'' flag.
""",
'EXAMPLES':
"""\
To delete the per-instance config from ``my-instance'', run:
$ {command} my-group --region=europe-west4 --instances=my-instance
This removes all metadata and detaches all disks that were defined in
the per-instance config (except for disks that are also defined in the
instance template, which remain attached).
"""
}

View File

@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for listing instance configs of a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.api_lib.compute import request_helper
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class List(base.ListCommand):
"""List per-instance configs of a managed instance group."""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser, operation_type='list instance configs for')
parser.display_info.AddFormat('yaml')
base.URI_FLAG.RemoveFromParser(parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.
ResolveAsResource)(
args,
resources,
scope_lister=compute_flags.GetDefaultScopeLister(client),
)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request = (client.messages.
ComputeInstanceGroupManagersListPerInstanceConfigsRequest)(
instanceGroupManager=igm_ref.Name(),
project=igm_ref.project,
zone=igm_ref.zone,
)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.apitools_client.regionInstanceGroupManagers
request = (
client.messages.
ComputeRegionInstanceGroupManagersListPerInstanceConfigsRequest)(
instanceGroupManager=igm_ref.Name(),
project=igm_ref.project,
region=igm_ref.region,
)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
errors = []
results = list(
request_helper.MakeRequests(
requests=[(service, 'ListPerInstanceConfigs', request)],
http=client.apitools_client.http,
batch_url=client.batch_url,
errors=errors))
if errors:
utils.RaiseToolException(errors)
return instance_groups_utils.UnwrapResponse(results, 'items')
List.detailed_help = {
'brief':
'List per-instance configs of a managed instance group.',
'DESCRIPTION':
"""\
*{command}* lists per-instance configs for each instance with preserved
resources (like disks). The list is presented by default in the form of
a tree (YAML) due to a potential for having multiple resources defined
in a single per-instance config.
""",
'EXAMPLES':
"""\
To list all the per-instance configs for the managed instance group
``my-group'', run:
$ {command} my-group --region=europe-west4
"""
}

View File

@@ -0,0 +1,485 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for updating managed instance config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute.operations import poller
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed.instance_configs import instance_configs_getter
from googlecloudsdk.command_lib.compute.instance_groups.managed.instance_configs import instance_configs_messages
from googlecloudsdk.command_lib.compute.instance_groups.managed.instance_configs import instance_disk_getter
import six
@base.ReleaseTracks(base.ReleaseTrack.GA)
class UpdateGA(base.UpdateCommand):
"""Update per-instance config of a managed instance group."""
@staticmethod
def _PatchDiskData(messages, preserved_disk, update_disk_data):
"""Patch preserved disk according to arguments of `update_disk_data`."""
auto_delete = update_disk_data.get('auto-delete')
if update_disk_data.get('source'):
preserved_disk.source = update_disk_data.get('source')
if update_disk_data.get('mode'):
preserved_disk.mode = instance_configs_messages.GetMode(
messages=messages, mode=update_disk_data.get('mode'))
if auto_delete:
preserved_disk.autoDelete = auto_delete.GetAutoDeleteEnumValue(
messages.PreservedStatePreservedDisk.AutoDeleteValueValuesEnum)
return preserved_disk
@staticmethod
def _UpdateStatefulDisks(messages, per_instance_config, disks_to_update_dict,
disks_to_remove_set, disk_getter):
"""Patch and return the updated list of stateful disks."""
new_stateful_disks = []
existing_disks = ((
per_instance_config.preservedState.disks.additionalProperties)
if per_instance_config.preservedState.disks else [])
removed_stateful_disks_set = set()
for current_stateful_disk in existing_disks:
disk_name = current_stateful_disk.key
# Disk to be removed
if disk_name in disks_to_remove_set:
removed_stateful_disks_set.add(disk_name)
continue
# Disk to be updated
if disk_name in disks_to_update_dict:
UpdateGA._PatchDiskData(messages, current_stateful_disk.value,
disks_to_update_dict[disk_name])
del disks_to_update_dict[disk_name]
new_stateful_disks.append(current_stateful_disk)
# Verify that there are no extraneous disks to be removed.
unremoved_stateful_disks_set = (
disks_to_remove_set.difference(removed_stateful_disks_set))
if unremoved_stateful_disks_set:
raise exceptions.InvalidArgumentException(
parameter_name='--remove-stateful-disk',
message=('The following are invalid stateful disks: `{0}`'.format(
','.join(unremoved_stateful_disks_set))))
for update_stateful_disk in disks_to_update_dict.values():
new_stateful_disks.append(
instance_configs_messages.MakePreservedStateDiskEntry(
messages=messages,
stateful_disk_data=update_stateful_disk,
disk_getter=disk_getter))
return new_stateful_disks
@staticmethod
def _UpdateStatefulMetadata(messages, per_instance_config,
update_stateful_metadata,
remove_stateful_metadata):
"""Patch and return updated stateful metadata."""
existing_metadata = []
if per_instance_config.preservedState.metadata:
existing_metadata = (per_instance_config.preservedState.metadata
.additionalProperties)
new_stateful_metadata = {
metadata.key: metadata.value
for metadata in existing_metadata
}
for metadata_key in remove_stateful_metadata or []:
if metadata_key in new_stateful_metadata:
del new_stateful_metadata[metadata_key]
else:
raise exceptions.InvalidArgumentException(
parameter_name='--remove-stateful-metadata',
message=('stateful metadata key to remove `{0}` does not exist in'
' the given instance config'.format(metadata_key)))
new_stateful_metadata.update(update_stateful_metadata)
return new_stateful_metadata
def _CombinePerInstanceConfigMessage(self, holder, per_instance_config,
instance_ref, args):
update_stateful_disks = args.stateful_disk
remove_stateful_disks = args.remove_stateful_disks
update_stateful_metadata = args.stateful_metadata
remove_stateful_metadata = args.remove_stateful_metadata
messages = holder.client.messages
# Patch stateful disks.
disk_getter = instance_disk_getter.InstanceDiskGetter(
instance_ref=instance_ref, holder=holder)
disks_to_remove_set = set(remove_stateful_disks or [])
disks_to_update_dict = {
update_stateful_disk.get('device-name'): update_stateful_disk
for update_stateful_disk in (update_stateful_disks or [])
}
new_stateful_disks = UpdateGA._UpdateStatefulDisks(
messages, per_instance_config, disks_to_update_dict,
disks_to_remove_set, disk_getter)
# Patch stateful metadata.
new_stateful_metadata = UpdateGA._UpdateStatefulMetadata(
messages, per_instance_config, update_stateful_metadata,
remove_stateful_metadata)
per_instance_config.preservedState.disks = (
messages.PreservedState.DisksValue(
additionalProperties=new_stateful_disks))
per_instance_config.preservedState.metadata = (
messages.PreservedState.MetadataValue(additionalProperties=[
instance_configs_messages.MakePreservedStateMetadataEntry(
messages, key=key, value=value)
for key, value in sorted(six.iteritems(new_stateful_metadata))
]))
UpdateGA._PatchStatefulInternalIPs(
messages=messages,
per_instance_config=per_instance_config,
ips_to_update=args.stateful_internal_ip,
ips_to_remove=args.remove_stateful_internal_ips,
)
UpdateGA._PatchStatefulExternalIPs(
messages=messages,
per_instance_config=per_instance_config,
ips_to_update=args.stateful_external_ip,
ips_to_remove=args.remove_stateful_external_ips,
)
return per_instance_config
@staticmethod
def _PatchStatefulInternalIPs(
messages, per_instance_config, ips_to_update, ips_to_remove
):
"""Patch and return the updated list of stateful internal IPs."""
existing_ips = (
per_instance_config.preservedState.internalIPs.additionalProperties
if per_instance_config.preservedState.internalIPs
else []
)
ips_to_update_dict = {
(
ip.get(
'interface-name',
instance_groups_flags.STATEFUL_IP_DEFAULT_INTERFACE_NAME,
)
): ip
for ip in iter(ips_to_update or [])
}
UpdateGA._VerifyStatefulIPsToRemoveSet(
'--remove-stateful-internal-ips', existing_ips, ips_to_remove
)
new_stateful_ips, remaining_ips_to_update = UpdateGA._UpdateExistingIPs(
messages, existing_ips, ips_to_update_dict, ips_to_remove
)
new_stateful_ips.extend(
UpdateGA._CreateInternalIPs(messages, remaining_ips_to_update)
)
per_instance_config.preservedState.internalIPs = (
messages.PreservedState.InternalIPsValue(
additionalProperties=new_stateful_ips
)
)
@staticmethod
def _PatchStatefulExternalIPs(
messages, per_instance_config, ips_to_update, ips_to_remove
):
"""Patch and return the updated list of stateful external IPs."""
existing_ips = (
per_instance_config.preservedState.externalIPs.additionalProperties
if per_instance_config.preservedState.externalIPs
else []
)
ips_to_update_dict = {
(
ip.get(
'interface-name',
instance_groups_flags.STATEFUL_IP_DEFAULT_INTERFACE_NAME,
)
): ip
for ip in iter(ips_to_update or [])
}
UpdateGA._VerifyStatefulIPsToRemoveSet(
'--remove-stateful-external-ips', existing_ips, ips_to_remove
)
new_stateful_ips, remaining_ips_to_update = UpdateGA._UpdateExistingIPs(
messages, existing_ips, ips_to_update_dict, ips_to_remove
)
new_stateful_ips.extend(
UpdateGA._CreateExternalIPs(messages, remaining_ips_to_update)
)
per_instance_config.preservedState.externalIPs = (
messages.PreservedState.ExternalIPsValue(
additionalProperties=new_stateful_ips
)
)
@staticmethod
def _CreateInstanceReference(holder, igm_ref, instance_name):
"""Creates reference to instance in instance group (zonal or regional)."""
if instance_name.startswith('https://') or instance_name.startswith(
'http://'):
return holder.resources.ParseURL(instance_name)
instance_references = (
managed_instance_groups_utils.CreateInstanceReferences)(
holder=holder, igm_ref=igm_ref, instance_names=[instance_name])
if not instance_references:
raise managed_instance_groups_utils.ResourceCannotBeResolvedException(
'Instance name {0} cannot be resolved'.format(instance_name))
return instance_references[0]
@classmethod
def Args(cls, parser):
instance_groups_flags.GetInstanceGroupManagerArg(
region_flag=True).AddArgument(
parser, operation_type='update per-instance config for')
instance_groups_flags.AddMigStatefulFlagsForUpdateInstanceConfigs(parser)
instance_groups_flags.AddMigStatefulUpdateInstanceFlag(parser)
instance_groups_flags.AddMigStatefulIPsFlagsForUpdateInstanceConfigs(parser)
def _ValidateStatefulFlagsForInstanceConfigs(self, args, per_instance_config):
instance_groups_flags.ValidateMigStatefulFlagsForInstanceConfigs(
args, for_update=True)
instance_groups_flags.ValidateMigStatefulIPFlagsForInstanceConfigs(
args,
UpdateGA._GetInterfacesWithInternalAddresses(per_instance_config),
UpdateGA._GetInterfacesWithExternalAddresses(per_instance_config),
for_update=True,
)
@staticmethod
def _GetExistingInterfaceNames(existing_ips):
return map(lambda x: x.key, existing_ips)
@staticmethod
def _VerifyStatefulIPsToRemoveSet(
remove_ips_flag_name, existing_ips, ips_to_remove
):
"""Verify that there are no extraneous IP interfaces to be removed."""
ips_to_remove_set = set(ips_to_remove or [])
existing_interfaces = UpdateGA._GetExistingInterfaceNames(existing_ips)
extraneous_interfaces = ips_to_remove_set.difference(existing_interfaces)
if extraneous_interfaces:
raise exceptions.InvalidArgumentException(
parameter_name=remove_ips_flag_name,
message=(
'The following are invalid stateful IPs to remove: `{0}`'.format(
','.join(extraneous_interfaces)
)
),
)
@staticmethod
def _UpdateExistingIPs(
messages, existing_ips, ips_to_update_dict, ips_to_remove
):
new_stateful_ips = []
remaining_ips_to_update = dict(ips_to_update_dict)
ips_to_remove_set = set(ips_to_remove or [])
for current_stateful_ip in existing_ips:
interface_name = current_stateful_ip.key
# Interface to be removed.
if interface_name in ips_to_remove_set:
continue
# Interface to be updated.
if interface_name in remaining_ips_to_update:
instance_configs_messages.PatchPreservedStateNetworkIpEntry(
messages,
current_stateful_ip.value,
remaining_ips_to_update[interface_name],
)
del remaining_ips_to_update[interface_name]
new_stateful_ips.append(current_stateful_ip)
return new_stateful_ips, remaining_ips_to_update
@staticmethod
def _CreateInternalIPs(messages, new_ips_dict):
new_stateful_ips = []
for update_stateful_ip in new_ips_dict.values():
new_stateful_ips.append(
instance_configs_messages.MakePreservedStateInternalNetworkIpEntry(
messages=messages, stateful_ip=update_stateful_ip
)
)
return new_stateful_ips
@staticmethod
def _CreateExternalIPs(messages, new_ips_dict):
new_stateful_ips = []
for update_stateful_ip in new_ips_dict.values():
new_stateful_ips.append(
instance_configs_messages.MakePreservedStateExternalNetworkIpEntry(
messages=messages, stateful_ip=update_stateful_ip
)
)
return new_stateful_ips
@staticmethod
def _GetInterfacesWithInternalAddresses(per_instance_config):
existing_ips = (
per_instance_config.preservedState.internalIPs.additionalProperties
if per_instance_config.preservedState.internalIPs
else []
)
return UpdateGA._GetExistingInterfaceNames(existing_ips)
@staticmethod
def _GetInterfacesWithExternalAddresses(per_instance_config):
existing_ips = (
per_instance_config.preservedState.externalIPs.additionalProperties
if per_instance_config.preservedState.externalIPs
else []
)
return UpdateGA._GetExistingInterfaceNames(existing_ips)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.
ResolveAsResource)(
args,
resources,
scope_lister=compute_flags.GetDefaultScopeLister(client),
)
instance_ref = self._CreateInstanceReference(
holder=holder, igm_ref=igm_ref, instance_name=args.instance)
configs_getter = (
instance_configs_getter.InstanceConfigsGetterWithSimpleCache)(
client)
configs_getter.check_if_instance_config_exists(
igm_ref=igm_ref, instance_ref=instance_ref, should_exist=True)
per_instance_config = configs_getter.get_instance_config(
igm_ref=igm_ref, instance_ref=instance_ref)
self._ValidateStatefulFlagsForInstanceConfigs(args, per_instance_config)
per_instance_config_message = self._CombinePerInstanceConfigMessage(
holder, per_instance_config, instance_ref, args)
operation_ref = instance_configs_messages.CallPerInstanceConfigUpdate(
holder=holder,
igm_ref=igm_ref,
per_instance_config_message=per_instance_config_message)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = holder.client.apitools_client.instanceGroupManagers
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = holder.client.apitools_client.regionInstanceGroupManagers
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
operation_poller = poller.Poller(service)
update_result = waiter.WaitFor(operation_poller, operation_ref,
'Updating instance config.')
if args.update_instance:
apply_operation_ref = (
instance_configs_messages.CallApplyUpdatesToInstances)(
holder=holder,
igm_ref=igm_ref,
instances=[six.text_type(instance_ref)],
minimal_action=args.instance_update_minimal_action)
return waiter.WaitFor(operation_poller, apply_operation_ref,
'Applying updates to instances.')
return update_result
UpdateGA.detailed_help = {
'brief': 'Update per-instance config of a managed instance group.',
'DESCRIPTION': """\
*{command}* updates the per-instance config of an instance controlled by
a Compute Engine managed instance group. The command lets you
change the list of instance-specific stateful resources, that is, the
list of resources that are preserved during instance restarts and
recreations.
Changes are applied immediately to the corresponding instances, by
performing the necessary action (for example, REFRESH), unless
overridden by providing the ``--no-update-instance'' flag.
""",
'EXAMPLES': """\
To updates the stateful disk ``my-disk-3'' to the image provided by
``source'', and clear ``my-disk1'' and ``my-disk2'' as stateful
disks, and to add stateful metadata ``my-key'': ``my-value'', on
instance ``my-instance'', run:
$ {{command}} {group} {region} {instance} {disk} {remove_disks} {meta}
If ``my-disk-3'' did not exist previously in the per-instance config,
and if it does not exist in the group's instance template, then the
command adds ``my-disk-3'' to ``my-instance''. The command also removes
stateful configuration for ``my-disk-1'' and ``my-disk-2''; if these
disk are not defined in the group's instance template, then they are
detached.
To update a per-instance configuration with a stateful internal IP
``192.168.0.10'', on instance ``my-instance'', run:
$ {{command}} {group} {region} {instance} {internal_ip}
To update a per-instance configuration to remove a stateful external IP
that's defined in network interface nic0, on instance my-instance, run:
$ {{command}} {group} {region} {instance} {remove_internal_ip}
""".format(
group='my-group',
region='--region=europe-west4',
instance='--instance=my-instance',
disk=(
'--stateful-disk=device-name=my-disk-3,source='
'projects/my-project/zones/us-central1-a/disks/my-disk-3'
),
remove_disks='--remove-stateful-disks=my-disk-1,my-disk-2',
meta="--stateful-metadata='my-key=my-value'",
internal_ip=(
'--stateful-internal-ip=address=192.168.0.10,interface-name=nic0'
),
remove_internal_ip='--remove-stateful-internal-ips=nic0',
),
}
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class UpdateBeta(UpdateGA):
"""Update per-instance config of a managed instance group."""
@classmethod
def Args(cls, parser):
UpdateGA.Args(parser)
UpdateBeta.detailed_help = UpdateGA.detailed_help
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class UpdateAlpha(UpdateBeta):
"""Update per-instance config of a managed instance group."""
@classmethod
def Args(cls, parser):
UpdateBeta.Args(parser)
UpdateAlpha.detailed_help = UpdateBeta.detailed_help

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for listing managed instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import lister
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags
from googlecloudsdk.core import log
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.GA,
base.ReleaseTrack.ALPHA)
class List(base.ListCommand):
"""List Compute Engine managed instance groups."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat(flags.DEFAULT_CREATE_OR_LIST_FORMAT)
lister.AddMultiScopeListerFlags(parser, zonal=True, regional=True)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
request_data = lister.ParseMultiScopeFlags(args, holder.resources)
list_implementation = lister.MultiScopeLister(
client,
zonal_service=client.apitools_client.instanceGroupManagers,
regional_service=client.apitools_client.regionInstanceGroupManagers,
aggregation_service=client.apitools_client.instanceGroupManagers)
migs = lister.Invoke(request_data, list_implementation)
(self._had_errors,
results) = managed_instance_groups_utils.AddAutoscaledPropertyToMigs(
list(migs), client, holder.resources)
return results
def Epilog(self, unused_resources_were_displayed):
if self._had_errors:
log.err.Print('(*) - there are errors in your autoscaling setup, please '
'describe the resource to see details')
List.detailed_help = base_classes.GetMultiScopeListerHelp(
'managed instance groups',
[base_classes.ScopeType.regional_scope, base_classes.ScopeType.zonal_scope])

View File

@@ -0,0 +1,132 @@
# -*- 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.
"""managed-instance-groups list-errors command.
Command for listing errors that are produced by managed instances in a managed
instance group.
"""
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.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class ListErrors(base.ListCommand):
"""List errors produced by managed instances in a managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""\
table(instanceActionDetails.instance:label=INSTANCE_URL,
instanceActionDetails.action:label=ACTION,
error.code:label=ERROR_CODE,
error.message:label=ERROR_MESSAGE,
timestamp:label=TIMESTAMP,
instanceActionDetails.version.instance_template:label=INSTANCE_TEMPLATE,
instanceActionDetails.version.name:label=VERSION_NAME
)""")
parser.display_info.AddUriFunc(
instance_groups_utils.UriFuncForListInstanceRelatedObjects)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
.ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client)))
if hasattr(group_ref, 'zone'):
service = client.apitools_client.instanceGroupManagers
request = (
client.messages.ComputeInstanceGroupManagersListErrorsRequest(
instanceGroupManager=group_ref.Name(),
zone=group_ref.zone,
project=group_ref.project))
elif hasattr(group_ref, 'region'):
service = client.apitools_client.regionInstanceGroupManagers
request = (
client.messages.ComputeRegionInstanceGroupManagersListErrorsRequest(
instanceGroupManager=group_ref.Name(),
region=group_ref.region,
project=group_ref.project))
batch_size = 500
if args.page_size is not None:
batch_size = args.page_size
results = list_pager.YieldFromList(
service,
request=request,
method='ListErrors',
field='items',
batch_size=batch_size,
)
return results
ListErrors.detailed_help = {
'brief':
'List errors produced by managed instances in a managed instance group.',
'DESCRIPTION':
"""\
*{command}*
List errors that are produced by managed instances in a managed instance
group.
The required permission to execute this command is
`compute.instanceGroupManagers.list`. If needed, you can include this
permission in a custom IAM role, or choose any of the following
preexisting IAM roles that contain this particular permission:
* Compute Admin
* Compute Viewer
* Compute Instance Admin (v1)
* Compute Instance Admin (beta)
* Compute Network Admin
* Editor
* Owner
* Security Reviewer
* Viewer
For more information regarding permissions required by managed
instance groups, refer to Compute Engine's access control guide:
https://cloud.google.com/compute/docs/access/iam#managed-instance-groups-and-iam.
""",
'EXAMPLES':
"""\
To list errors on managed instance group 'my-group', run:
$ {command} \\
my-group --format=yaml
"""
}

View File

@@ -0,0 +1,166 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""managed-instance-groups list-instances command.
It's an alias for the instance-groups list-instances command.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.api_lib.compute import request_helper
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class ListInstances(base.ListCommand):
"""List Compute Engine instances present in managed instance group."""
@staticmethod
def Args(parser):
instance_groups_flags.AddListInstancesOutputFormat(parser)
parser.display_info.AddUriFunc(
instance_groups_utils.UriFuncForListInstanceRelatedObjects)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
"""Retrieves response with instance in the instance group."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.
ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client)))
if hasattr(group_ref, 'zone'):
service = client.apitools_client.instanceGroupManagers
request = (client.messages.
ComputeInstanceGroupManagersListManagedInstancesRequest(
instanceGroupManager=group_ref.Name(),
zone=group_ref.zone,
project=group_ref.project))
elif hasattr(group_ref, 'region'):
service = client.apitools_client.regionInstanceGroupManagers
request = (client.messages.
ComputeRegionInstanceGroupManagersListManagedInstancesRequest(
instanceGroupManager=group_ref.Name(),
region=group_ref.region,
project=group_ref.project))
errors = []
results = list(request_helper.MakeRequests(
requests=[(service, 'ListManagedInstances', request)],
http=client.apitools_client.http,
batch_url=client.batch_url,
errors=errors))
if errors:
utils.RaiseToolException(errors)
return results
ListInstances.detailed_help = {
'brief':
'List instances present in the managed instance group',
'DESCRIPTION':
"""\
*{command}* lists instances in a managed instance group.
The required permission to execute this command is
`compute.instanceGroupManagers.list`. If needed, you can include this
permission, or choose any of the following preexisting IAM roles
that contain this particular permission:
* Compute Admin
* Compute Viewer
* Compute Instance Admin (v1)
* Compute Instance Admin (beta)
* Compute Network Admin
* Editor
* Owner
* Security Reviewer
* Viewer
For more information regarding permissions required by managed
instance groups, refer to Compute Engine's access control guide :
https://cloud.google.com/compute/docs/access/iam#managed-instance-groups-and-iam.
""",
'EXAMPLES':
"""\
To see additional details about the instances in a managed instance
group `my-group`, including per-instance overrides, run:
$ {command} \\
my-group --format=yaml
"""
}
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class ListInstancesBeta(ListInstances):
"""List Compute Engine instances present in managed instance group."""
@staticmethod
def Args(parser):
instance_groups_flags.AddListInstancesOutputFormat(
parser, release_track=base.ReleaseTrack.BETA)
parser.display_info.AddUriFunc(
instance_groups_utils.UriFuncForListInstanceRelatedObjects)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
ListInstancesBeta.detailed_help = ListInstances.detailed_help
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ListInstancesAlpha(ListInstances):
"""List Compute Engine instances present in managed instance group."""
def Run(self, args):
managed_instances = super().Run(args)
# if uri and format is not provided by the user, then change the output to
# hide dynamic fields if they are not present in fetched instances
if not args.uri and not args.IsSpecified('format'):
args.format = (
instance_groups_flags.GetListInstancesOutputWithDynamicFields(
managed_instances, base.ReleaseTrack.ALPHA
)
)
return managed_instances
@staticmethod
def Args(parser):
instance_groups_flags.AddListInstancesOutputFormat(
parser, release_track=base.ReleaseTrack.ALPHA)
parser.display_info.AddUriFunc(
instance_groups_utils.UriFuncForListInstanceRelatedObjects)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
ListInstancesAlpha.detailed_help = ListInstancesBeta.detailed_help

View File

@@ -0,0 +1,112 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for recreating instances managed by a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
def _AddArgs(parser):
"""Adds args."""
parser.add_argument(
'--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
required=True,
help='Names of instances to recreate.')
class RecreateInstances(base.Command):
"""Recreate instances managed by a managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(project(),
zone(),
instanceName:label=INSTANCE,
status)""")
_AddArgs(parser=parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instances_holder_field = 'instanceGroupManagersRecreateInstancesRequest'
request = client.messages.ComputeInstanceGroupManagersRecreateInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersRecreateInstancesRequest=client.messages
.InstanceGroupManagersRecreateInstancesRequest(instances=[]),
project=igm_ref.project,
zone=igm_ref.zone)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instances_holder_field = 'regionInstanceGroupManagersRecreateRequest'
request = client.messages.ComputeRegionInstanceGroupManagersRecreateInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersRecreateRequest=client.messages
.RegionInstanceGroupManagersRecreateRequest(instances=[]),
project=igm_ref.project,
region=igm_ref.region,
)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='RecreateInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances)
RecreateInstances.detailed_help = {
'brief':
'Recreate instances managed by a managed instance group.',
'DESCRIPTION':
"""
*{command}* is used to recreate one or more instances in a managed
instance group. The underlying virtual machine instances are deleted and
recreated based on the latest instance template configured for the managed
instance group.
The command returns the operation status per instance, which might be ``FAIL'',
``SUCCESS'', or ``MEMBER_NOT_FOUND''. ``MEMBER_NOT_FOUND'' is returned only for
regional groups when the gcloud command-line tool wasn't able to resolve the
zone from the instance name.
""",
}

View File

@@ -0,0 +1,292 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for setting size of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import sys
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as managed_flags
def _AddArgs(parser, creation_retries, suspended_stopped_sizes):
"""Adds args."""
managed_flags.AddMigSizeFlag(parser, required=not suspended_stopped_sizes)
if creation_retries:
parser.add_argument(
'--creation-retries',
action='store_true',
default=True,
help='When instance creation fails retry it.')
if suspended_stopped_sizes:
parser.add_argument(
'--suspended-size',
type=arg_parsers.BoundedInt(0, sys.maxsize, unlimited=True),
help='Target number of suspended instances in managed instance group.')
parser.add_argument(
'--stopped-size',
type=arg_parsers.BoundedInt(0, sys.maxsize, unlimited=True),
help='Target number of stopped instances in managed instance group.')
# TODO(b/345166947) Remove universe annotation once b/341682289 is resolved.
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Resize(base.Command):
"""Set managed instance group size."""
@staticmethod
def Args(parser):
_AddArgs(
parser=parser, creation_retries=False, suspended_stopped_sizes=False)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def CreateGroupReference(self, client, resources, args):
return (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.
ResolveAsResource(
args, resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client)))
@staticmethod
def _MakeIgmResizeRequest(client, igm_ref, args):
service = client.apitools_client.instanceGroupManagers
request = client.messages.ComputeInstanceGroupManagersResizeRequest(
instanceGroupManager=igm_ref.Name(),
size=args.size,
project=igm_ref.project,
zone=igm_ref.zone)
return client.MakeRequests([(service, 'Resize', request)])
@staticmethod
def _MakeRmigResizeRequest(client, igm_ref, args):
service = client.apitools_client.regionInstanceGroupManagers
request = client.messages.ComputeRegionInstanceGroupManagersResizeRequest(
instanceGroupManager=igm_ref.Name(),
size=args.size,
project=igm_ref.project,
region=igm_ref.region)
return client.MakeRequests([(service, 'Resize', request)])
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = self.CreateGroupReference(client, holder.resources, args)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
return self._MakeIgmResizeRequest(client, igm_ref, args)
if igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
return self._MakeRmigResizeRequest(client, igm_ref, args)
raise ValueError('Unknown reference type {0}'.format(igm_ref.Collection()))
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class ResizeBeta(Resize):
"""Set managed instance group size."""
@staticmethod
def Args(parser):
_AddArgs(
parser=parser, creation_retries=True, suspended_stopped_sizes=False)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
@staticmethod
def _MakeIgmResizeAdvancedRequest(client, igm_ref, args):
service = client.apitools_client.instanceGroupManagers
request = (
client.messages.ComputeInstanceGroupManagersResizeAdvancedRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersResizeAdvancedRequest=(
client.messages.InstanceGroupManagersResizeAdvancedRequest(
targetSize=args.size,
noCreationRetries=not args.creation_retries,
)),
project=igm_ref.project,
zone=igm_ref.zone))
return client.MakeRequests([(service, 'ResizeAdvanced', request)])
@staticmethod
def _MakeRmigResizeAdvancedRequest(client, igm_ref, args):
service = client.apitools_client.regionInstanceGroupManagers
request = (
client.messages
.ComputeRegionInstanceGroupManagersResizeAdvancedRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersResizeAdvancedRequest=(
client.messages
.RegionInstanceGroupManagersResizeAdvancedRequest(
targetSize=args.size,
noCreationRetries=not args.creation_retries,
)),
project=igm_ref.project,
region=igm_ref.region))
return client.MakeRequests([(service, 'ResizeAdvanced', request)])
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = self.CreateGroupReference(client, holder.resources, args)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
return self._MakeIgmResizeAdvancedRequest(client, igm_ref, args)
if igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
# user specifies --no-creation-retries flag explicitly
if not args.creation_retries:
return self._MakeRmigResizeAdvancedRequest(client, igm_ref, args)
return self._MakeRmigResizeRequest(client, igm_ref, args)
raise ValueError('Unknown reference type {0}'.format(igm_ref.Collection()))
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ResizeAlpha(ResizeBeta):
"""Set managed instance group sizes."""
@staticmethod
def Args(parser):
_AddArgs(parser=parser, creation_retries=True, suspended_stopped_sizes=True)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
@staticmethod
def _ValidateArgs(args):
if (args.size is None and args.suspended_size is None and
args.stopped_size is None):
raise exceptions.OneOfArgumentsRequiredException(
['--size', '--suspended-size', '--stopped-size'],
'At least one of the sizes must be specified')
if not args.creation_retries:
if args.size is None:
raise exceptions.RequiredArgumentException(
'--size',
'Size must be specified when --no-creation-retries flag is used.')
if args.suspended_size is not None:
raise exceptions.ConflictingArgumentsException('--suspended-size',
'--no-creation-retries')
if args.stopped_size is not None:
raise exceptions.ConflictingArgumentsException('--stopped-size',
'--no-creation-retries')
@staticmethod
def _MakeIgmPatchResource(client, args):
igm_patch_resource = client.messages.InstanceGroupManager()
if args.size is not None:
igm_patch_resource.targetSize = args.size
if args.suspended_size is not None:
igm_patch_resource.targetSuspendedSize = args.suspended_size
if args.stopped_size is not None:
igm_patch_resource.targetStoppedSize = args.stopped_size
return igm_patch_resource
@staticmethod
def _MakeIgmPatchRequest(client, igm_ref, args):
service = client.apitools_client.instanceGroupManagers
request = client.messages.ComputeInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=ResizeAlpha._MakeIgmPatchResource(
client, args),
project=igm_ref.project,
zone=igm_ref.zone)
return client.MakeRequests([(service, 'Patch', request)])
@staticmethod
def _MakeRmigPatchRequest(client, igm_ref, args):
service = client.apitools_client.regionInstanceGroupManagers
request = client.messages.ComputeRegionInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=ResizeAlpha._MakeIgmPatchResource(
client, args),
project=igm_ref.project,
region=igm_ref.region)
return client.MakeRequests([(service, 'Patch', request)])
# pylint: disable=line-too-long
# | scope | creation_retries arg | suspended or stopped _size arg | method |
# |----------|----------------------|--------------------------------|-------------------------------|
# | zonal | True | True | Patch |
# | zonal | True | False | ResizeAdvanced |
# | zonal | False | True | ConflictingArgumentsException |
# | zonal | False | False | ResizeAdvanced |
# | regional | True | True | Patch |
# | regional | True | False | Resize TODO(b/178852691) |
# | regional | False | True | ConflictingArgumentsException |
# | regional | False | False | ResizeAdvanced |
# pylint: enable=line-too-long
def Run(self, args):
self._ValidateArgs(args)
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = self.CreateGroupReference(client, holder.resources, args)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
# user specifies --no-creation-retries flag explicitly
if not args.creation_retries:
return self._MakeIgmResizeAdvancedRequest(client, igm_ref, args)
return self._MakeIgmPatchRequest(client, igm_ref, args)
if igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
# user specifies --no-creation-retries flag explicitly
if not args.creation_retries:
return self._MakeRmigResizeAdvancedRequest(client, igm_ref, args)
if args.suspended_size is not None or args.stopped_size is not None:
return self._MakeRmigPatchRequest(client, igm_ref, args)
# TODO(b/178852691): Redirect whole alpha traffic to ResizeAdvanced,
# even if the "no-creation-retries" flag is not set. This would be the
# intended shape of this code, and this is would be also consistent with
# zonal version. Instead of doing it immediately, this TODO is added to
# get the desired gradual launch behavior.
return self._MakeRmigResizeRequest(client, igm_ref, args)
raise ValueError('Unknown reference type {0}'.format(igm_ref.Collection()))
Resize.detailed_help = {
'brief': 'Set managed instance group size.',
'DESCRIPTION': """
*{command}* resize a managed instance group to a provided size.
If you resize down, the Instance Group Manager service deletes instances from
the group until the group reaches the desired size. Instances are deleted
in arbitrary order but the Instance Group Manager takes into account some
considerations before it chooses which instance to delete. For more information,
see https://cloud.google.com/compute/docs/reference/rest/v1/instanceGroupManagers/resize.
If you resize up, the service adds instances to the group using the current
instance template until the group reaches the desired size.
""",
}
ResizeBeta.detailed_help = Resize.detailed_help
ResizeAlpha.detailed_help = Resize.detailed_help

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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 reading and manipulating ResizeRequests."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class ManagedInstanceGroupsResizeRequests(base.Group):
"""List, create, delete, cancel, and describe ResizeRequests."""

View File

@@ -0,0 +1,298 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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 for cancelling queued managed instance group resize requests."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
DETAILED_HELP = {
'brief': 'Cancel a Compute Engine managed instance group resize request.',
'EXAMPLES': """
To cancel a resize request for a managed instance group, run the following command:
$ {command} my-mig --resize-requests=resize-request-1
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class Cancel(base.UpdateCommand):
"""Cancel a Compute Engine managed instance group resize request.
*{command}* cancels one or more Compute Engine managed instance group resize
requests.
You can only cancel a resize request when it is in the ACCEPTED state.
"""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
instance_groups_flags.MakeZonalInstanceGroupManagerArg().AddArgument(parser)
parser.add_argument(
'--resize-requests',
type=arg_parsers.ArgList(min_length=1),
metavar='RESIZE_REQUEST_NAMES',
required=True,
help='A list of comma-separated names of resize requests to cancel.',
)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.cancel requests.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
A list of URI paths of the successfully canceled resize requests.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MakeZonalInstanceGroupManagerArg()
igm_ref = self._GetIgmRef(args, holder, resource_arg)
resize_request_refs = self._CreateResizeRequestReferences(
args.resize_requests, igm_ref, holder.resources
)
return self._MakeRequests(holder.client, igm_ref, resize_request_refs)
def _GetIgmRef(self, args, holder, resource_arg):
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(holder.client),
)
return igm_ref
def _CreateResizeRequestReferences(
self, resize_request_names, igm_ref, resources
):
resize_request_references = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_name in resize_request_names:
resize_request_references.append(
resources.Parse(
resize_request_name,
{
'project': igm_ref.project,
'zone': igm_ref.zone,
'instanceGroupManager': igm_ref.instanceGroupManager,
},
collection='compute.instanceGroupManagerResizeRequests',
)
)
return resize_request_references
raise ValueError('Unknown reference type {0}'.format(igm_ref.Collection()))
def _MakeRequests(self, client, igm_ref, resize_request_refs):
requests = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_ref in resize_request_refs:
requests.append((
client.apitools_client.instanceGroupManagerResizeRequests,
'Cancel',
client.messages.ComputeInstanceGroupManagerResizeRequestsCancelRequest(
project=igm_ref.project,
zone=igm_ref.zone,
instanceGroupManager=igm_ref.instanceGroupManager,
resizeRequest=resize_request_ref.resizeRequest,
),
))
else:
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
return client.MakeRequests(requests)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CancelBeta(Cancel):
"""Cancel a Compute Engine managed instance group resize request.
*{command}* cancels one or more Compute Engine managed instance group resize
requests.
You can only cancel a resize request when it is in the ACCEPTED state.
"""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser
)
parser.add_argument(
'--resize-requests',
type=arg_parsers.ArgList(min_length=1),
metavar='RESIZE_REQUEST_NAMES',
required=True,
help='A list of comma-separated names of resize requests to cancel.',
)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.cancel requests.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
A list of URI paths of the successfully canceled resize requests.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
igm_ref = self._GetIgmRef(args, holder, resource_arg)
resize_request_refs = self._CreateResizeRequestReferences(
args.resize_requests, igm_ref, holder.resources
)
return self._MakeRequests(holder.client, igm_ref, resize_request_refs)
def _CreateResizeRequestReferences(
self, resize_request_names, igm_ref, resources
):
resize_request_references = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_name in resize_request_names:
resize_request_references.append(
resources.Parse(
resize_request_name,
{
'project': igm_ref.project,
'zone': igm_ref.zone,
'instanceGroupManager': igm_ref.instanceGroupManager,
},
collection='compute.instanceGroupManagerResizeRequests',
)
)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
for resize_request_name in resize_request_names:
resize_request_references.append(
resources.Parse(
resize_request_name,
{
'project': igm_ref.project,
'region': igm_ref.region,
'instanceGroupManager': igm_ref.instanceGroupManager,
},
collection='compute.regionInstanceGroupManagerResizeRequests',
)
)
else:
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
return resize_request_references
def _MakeRequests(self, client, igm_ref, resize_request_refs):
requests = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_ref in resize_request_refs:
requests.append((
client.apitools_client.instanceGroupManagerResizeRequests,
'Cancel',
client.messages.ComputeInstanceGroupManagerResizeRequestsCancelRequest(
project=igm_ref.project,
zone=igm_ref.zone,
instanceGroupManager=igm_ref.instanceGroupManager,
resizeRequest=resize_request_ref.resizeRequest,
),
))
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
for resize_request_ref in resize_request_refs:
requests.append((
client.apitools_client.regionInstanceGroupManagerResizeRequests,
'Cancel',
client.messages.ComputeRegionInstanceGroupManagerResizeRequestsCancelRequest(
project=igm_ref.project,
region=igm_ref.region,
instanceGroupManager=igm_ref.instanceGroupManager,
resizeRequest=resize_request_ref.resizeRequest,
),
))
else:
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
return client.MakeRequests(requests)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CancelAlpha(CancelBeta):
"""Cancel a Compute Engine managed instance group resize request.
*{command}* cancels one or more Compute Engine managed instance group resize
requests.
You can only cancel a resize request when it is in the ACCEPTED state.
"""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser
)
rr_group = parser.add_group(mutex=True, required=True)
rr_group.add_argument(
'--resize-requests',
type=arg_parsers.ArgList(min_length=1),
metavar='RESIZE_REQUEST_NAMES',
required=False,
help='A list of comma-separated names of resize requests to cancel.',
)
rr_group.add_argument(
'--resize-request',
metavar='RESIZE_REQUEST_NAME',
type=str,
required=False,
help="""(ALPHA only) The name of the resize request to cancel.""",
)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.cancel request.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
A URI path of the successfully canceled resize request.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
igm_ref = self._GetIgmRef(args, holder, resource_arg)
if args.IsKnownAndSpecified('resize_request'):
resize_request_refs = self._CreateResizeRequestReferences(
[args.resize_request], igm_ref, holder.resources
)
else:
resize_request_refs = self._CreateResizeRequestReferences(
args.resize_requests, igm_ref, holder.resources
)
return self._MakeRequests(holder.client, igm_ref, resize_request_refs)

View File

@@ -0,0 +1,332 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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 for creating managed instance group resize requests."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed.resize_requests import flags as rr_flags
from googlecloudsdk.core.util import times
DETAILED_HELP = {
'brief': 'Create a Compute Engine managed instance group resize request.',
'EXAMPLES': """
To create a resize request for a managed instance group, run the following command:
$ {command} my-mig --resize-request=resize-request-1 --resize-by=1 --requested-run-duration=3d1h30s
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class Create(base.CreateCommand):
"""Create a Compute Engine managed instance group resize request."""
detailed_help = DETAILED_HELP
@classmethod
def _AddArgsGaCommon(cls, parser):
parser.add_argument(
'--resize-request',
metavar='RESIZE_REQUEST_NAME',
type=str,
required=True,
help="""The name of the resize request to create.""",
)
parser.add_argument(
'--requested-run-duration',
type=arg_parsers.Duration(),
required=False,
help="""The time you need the requested VMs to run before being
automatically deleted. The value must be formatted as the number of
days, hours, minutes, or seconds followed by `d`, `h`, `m`, and `s`
respectively. For example, specify `30m` for a duration of 30
minutes or `1d2h3m4s` for 1 day, 2 hours, 3 minutes, and 4 seconds.
The value must be between `10m` (10 minutes) and `7d` (7 days).
If you want the managed instance group to consume a reservation or use
FLEX_START provisioning model, then this flag is optional. Otherwise,
it's required.""",
)
@classmethod
def Args(cls, parser):
instance_groups_flags.MakeZonalInstanceGroupManagerArg().AddArgument(parser)
rr_flags.AddOutputFormat(parser, cls.ReleaseTrack())
cls._AddArgsGaCommon(parser)
parser.add_argument(
'--resize-by',
type=int,
required=True,
help="""The number of VMs to resize managed instance group by.""",
)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.insert request.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
List containing the created resize request.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MakeZonalInstanceGroupManagerArg()
igm_ref = self._GetIgmRef(args, holder, resource_arg)
requested_run_duration = None
if args.IsKnownAndSpecified('requested_run_duration'):
requested_run_duration = holder.client.messages.Duration(
seconds=args.requested_run_duration
)
resize_request = holder.client.messages.InstanceGroupManagerResizeRequest(
name=args.resize_request,
resizeBy=args.resize_by,
requestedRunDuration=requested_run_duration,
)
return self._MakeRequest(holder.client, igm_ref, resize_request)
def _GetIgmRef(self, args, holder, resource_arg):
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(holder.client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister,
)
return igm_ref
def _MakeRequest(self, client, igm_ref, resize_request):
request = (
client.messages.ComputeInstanceGroupManagerResizeRequestsInsertRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResizeRequest=resize_request,
project=igm_ref.project,
zone=igm_ref.zone,
)
)
return client.MakeRequests([(
client.apitools_client.instanceGroupManagerResizeRequests,
'Insert',
request,
)])
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CreateBeta(Create):
"""Create a Compute Engine managed instance group resize request."""
@classmethod
def Args(cls, parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser
)
rr_flags.AddOutputFormat(parser, cls.ReleaseTrack())
cls._AddArgsGaCommon(parser)
resize_by_instances_group = parser.add_group(mutex=True, required=True)
resize_by_instances_group.add_argument(
'--resize-by',
type=int,
help="""The number of instances to create with this resize request.
Instances have automatically-generated names. The group's target size
increases by this number.""",
)
resize_by_instances_group.add_argument(
'--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
help="""A comma-separated list of instance names. The number of names
you provide determines the number of instances to create with this
resize request. The group's target size increases by this count.""",
)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.insert request.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
igm_ref = self._GetIgmRef(args, holder, resource_arg)
requested_run_duration = None
if args.IsKnownAndSpecified('requested_run_duration'):
requested_run_duration = holder.client.messages.Duration(
seconds=args.requested_run_duration
)
resize_by = None
instances = []
if args.IsKnownAndSpecified('resize_by'):
resize_by = args.resize_by
else:
instances = args.instances
resize_request = holder.client.messages.InstanceGroupManagerResizeRequest(
name=args.resize_request,
resizeBy=resize_by,
instances=self._CreatePerInstanceConfigList(holder, instances),
requestedRunDuration=requested_run_duration,
)
return self._MakeRequest(holder.client, igm_ref, resize_request)
def _MakeRequest(self, client, igm_ref, resize_request):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
return client.MakeRequests([(
client.apitools_client.instanceGroupManagerResizeRequests,
'Insert',
client.messages.ComputeInstanceGroupManagerResizeRequestsInsertRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResizeRequest=resize_request,
project=igm_ref.project,
zone=igm_ref.zone,
),
)])
if igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
return client.MakeRequests([(
client.apitools_client.regionInstanceGroupManagerResizeRequests,
'Insert',
client.messages.ComputeRegionInstanceGroupManagerResizeRequestsInsertRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResizeRequest=resize_request,
project=igm_ref.project,
region=igm_ref.region,
),
)])
raise ValueError('Unknown reference type {0}'.format(igm_ref.Collection()))
def _CreatePerInstanceConfigList(self, holder, instances):
"""Creates a list of per instance configs for the given instances."""
return [
holder.client.messages.PerInstanceConfig(name=instance)
for instance in instances
]
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CreateAlpha(CreateBeta):
"""Create a Compute Engine managed instance group resize request."""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser
)
rr_flags.AddOutputFormat(parser, cls.ReleaseTrack())
cls._AddArgsGaCommon(parser)
count_resize_by_instances_group = parser.add_group(
mutex=True, required=True
)
count_resize_by_instances_group.add_argument(
'--count',
type=int,
hidden=True,
help="""(ALPHA only) The number of VMs to create.""",
)
count_resize_by_instances_group.add_argument(
'--resize-by',
type=int,
help="""The number of instances to create with this resize request.
Instances have automatically-generated names. The group's target size
increases by this number.""",
)
count_resize_by_instances_group.add_argument(
'--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
help="""A comma-separated list of instance names. The number of names
you provide determines the number of instances to create with this
resize request. The group's target size increases by this count.""",
)
valid_until_group = parser.add_group(
mutex=True, required=False, hidden=True
)
valid_until_group.add_argument(
'--valid-until-duration',
type=arg_parsers.Duration(),
help="""Relative deadline for waiting for capacity.""",
)
valid_until_group.add_argument(
'--valid-until-time',
type=arg_parsers.Datetime.Parse,
help="""Absolute deadline for waiting for capacity in RFC3339 text format.""",
)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.insert request.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
List containing the created resize request with its queuing policy.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
igm_ref = self._GetIgmRef(args, holder, resource_arg)
if args.IsKnownAndSpecified('valid_until_duration'):
queuing_policy = holder.client.messages.QueuingPolicy(
validUntilDuration=holder.client.messages.Duration(
seconds=args.valid_until_duration
)
)
elif args.IsKnownAndSpecified('valid_until_time'):
queuing_policy = holder.client.messages.QueuingPolicy(
validUntilTime=times.FormatDateTime(args.valid_until_time)
)
else:
queuing_policy = None
requested_run_duration = None
if args.IsKnownAndSpecified('requested_run_duration'):
requested_run_duration = holder.client.messages.Duration(
seconds=args.requested_run_duration
)
resize_by = None
instances = []
if args.IsKnownAndSpecified('resize_by'):
resize_by = args.resize_by
elif args.IsKnownAndSpecified('count'):
resize_by = args.count
else:
instances = args.instances
resize_request = holder.client.messages.InstanceGroupManagerResizeRequest(
name=args.resize_request,
resizeBy=resize_by,
instances=self._CreatePerInstanceConfigList(holder, instances),
queuingPolicy=queuing_policy,
requestedRunDuration=requested_run_duration,
)
return self._MakeRequest(holder.client, igm_ref, resize_request)

View File

@@ -0,0 +1,239 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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 for deleting managed instance group resize requests."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
DETAILED_HELP = {
'brief': 'Delete a Compute Engine managed instance group resize request.',
'EXAMPLES': """
To delete a resize request for a managed instance group, run the following command:
$ {command} my-mig --resize-requests=resize-request-1
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class Delete(base.DeleteCommand):
"""Delete a Compute Engine managed instance group resize request.
*{command}* deletes one or more Compute Engine managed instance
group resize requests.
You can only delete a request when it is in a state SUCCEEDED,
FAILED, or CANCELLED.
"""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
instance_groups_flags.MakeZonalInstanceGroupManagerArg().AddArgument(
parser
)
parser.add_argument(
'--resize-requests',
type=arg_parsers.ArgList(min_length=1),
metavar='RESIZE_REQUEST_NAMES',
required=True,
help='A list of comma-separated names of resize requests to delete.',
)
def Run(self, args):
"""Creates and issues multiple instanceGroupManagerResizeRequests.delete requests.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
A list of URI paths of the successfully deleted resize requests.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MakeZonalInstanceGroupManagerArg()
igm_ref = self._GetIgmRef(args, holder, resource_arg)
resize_requests_refs = self._CreateResizeRequestReferences(
args.resize_requests, igm_ref, holder.resources
)
utils.PromptForDeletion(resize_requests_refs)
return self._MakeRequests(holder.client, igm_ref, resize_requests_refs)
def _GetIgmRef(self, args, holder, resource_arg):
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = compute_flags.GetDefaultScopeLister(holder.client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister,
)
return igm_ref
def _CreateResizeRequestReferences(self, resize_requests, igm_ref, resources):
resize_request_references = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_name in resize_requests:
resize_request_references.append(resources.Parse(
resize_request_name,
{
'project': igm_ref.project,
'zone': igm_ref.zone,
'instanceGroupManager': igm_ref.instanceGroupManager,
},
collection='compute.instanceGroupManagerResizeRequests',
))
return resize_request_references
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
def _MakeRequests(self, client, igm_ref, resize_request_refs):
requests = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_ref in resize_request_refs:
requests.append((
client.apitools_client.instanceGroupManagerResizeRequests,
'Delete',
client.messages.ComputeInstanceGroupManagerResizeRequestsDeleteRequest(
project=resize_request_ref.project,
zone=resize_request_ref.zone,
instanceGroupManager=resize_request_ref.instanceGroupManager,
resizeRequest=resize_request_ref.resizeRequest,
),
))
return client.MakeRequests(requests)
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class DeleteBeta(Delete):
"""Delete a Compute Engine managed instance group resize request.
*{command}* deletes one or more Compute Engine managed instance
group resize requests.
You can only delete a request when it is in a state SUCCEEDED,
FAILED, or CANCELLED.
"""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser
)
parser.add_argument(
'--resize-requests',
type=arg_parsers.ArgList(min_length=1),
metavar='RESIZE_REQUEST_NAMES',
required=True,
help='A list of comma-separated names of resize requests to delete.',
)
def Run(self, args):
"""Creates and issues multiple instanceGroupManagerResizeRequests.delete requests."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
igm_ref = self._GetIgmRef(args, holder, resource_arg)
resize_requests_refs = self._CreateResizeRequestReferences(
args.resize_requests, igm_ref, holder.resources
)
utils.PromptForDeletion(resize_requests_refs)
return self._MakeRequests(holder.client, igm_ref, resize_requests_refs)
def _GetIgmRef(self, args, holder, resource_arg):
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = compute_flags.GetDefaultScopeLister(holder.client)
return resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister,
)
def _CreateResizeRequestReferences(self, resize_requests, igm_ref, resources):
resize_request_references = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_name in resize_requests:
resize_request_references.append(resources.Parse(
resize_request_name,
{
'project': igm_ref.project,
'zone': igm_ref.zone,
'instanceGroupManager': igm_ref.instanceGroupManager,
},
collection='compute.instanceGroupManagerResizeRequests',
))
return resize_request_references
if igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
for resize_request_name in resize_requests:
resize_request_references.append(resources.Parse(
resize_request_name,
{
'project': igm_ref.project,
'region': igm_ref.region,
'instanceGroupManager': igm_ref.instanceGroupManager,
},
collection='compute.regionInstanceGroupManagerResizeRequests',
))
return resize_request_references
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
def _MakeRequests(self, client, igm_ref, resize_request_refs):
requests = []
if igm_ref.Collection() == 'compute.instanceGroupManagers':
for resize_request_ref in resize_request_refs:
requests.append((
client.apitools_client.instanceGroupManagerResizeRequests,
'Delete',
client.messages.ComputeInstanceGroupManagerResizeRequestsDeleteRequest(
project=resize_request_ref.project,
zone=resize_request_ref.zone,
instanceGroupManager=resize_request_ref.instanceGroupManager,
resizeRequest=resize_request_ref.resizeRequest,
),
))
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
for resize_request_ref in resize_request_refs:
requests.append((
client.apitools_client.regionInstanceGroupManagerResizeRequests,
'Delete',
client.messages.ComputeRegionInstanceGroupManagerResizeRequestsDeleteRequest(
project=resize_request_ref.project,
region=resize_request_ref.region,
instanceGroupManager=resize_request_ref.instanceGroupManager,
resizeRequest=resize_request_ref.resizeRequest),
))
return client.MakeRequests(requests)

View File

@@ -0,0 +1,176 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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 for describing queued resources."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
DETAILED_HELP = {
'brief': (
'Describe a Compute Engine managed instance group resize request'
' resource.'
),
'EXAMPLES': """
To describe a resize request for a managed instance group, run the following command:
$ {command} my-mig --resize-request=resize-request-1
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class DescribeGA(base.DescribeCommand):
"""Describe a Compute Engine managed instance group resize request resource.
*{command}* describes a Compute Engine managed instance group resize request
resource.
"""
detailed_help = DETAILED_HELP
@staticmethod
def Args(parser):
instance_groups_flags.MakeZonalInstanceGroupManagerArg().AddArgument(
parser)
parser.add_argument(
'--resize-request',
metavar='RESIZE_REQUEST_NAME',
type=str,
required=True,
help="""The name of the resize request to describe.""")
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.get request.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
Detailed information about resize request.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MakeZonalInstanceGroupManagerArg()
igm_ref = self._GetIgmRef(args, holder, resource_arg)
return self._MakeRequest(args, holder, igm_ref)
@classmethod
def _GetIgmRef(cls, args, holder, resource_arg):
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(holder.client))
return igm_ref
@classmethod
def _MakeRequest(cls, args, holder, igm_ref):
client = holder.client
if igm_ref.Collection() == 'compute.instanceGroupManagers':
requests = [(
client.apitools_client.instanceGroupManagerResizeRequests,
'Get',
client.messages.ComputeInstanceGroupManagerResizeRequestsGetRequest(
project=igm_ref.project,
zone=igm_ref.zone,
instanceGroupManager=igm_ref.instanceGroupManager,
resizeRequest=args.resize_request,
),
)]
return client.MakeRequests(requests)[0]
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Describe(DescribeGA):
"""Describe a Compute Engine managed instance group resize request resource.
*{command}* describes a Compute Engine managed instance group resize request
resource.
"""
detailed_help = DETAILED_HELP
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
parser.add_argument(
'--resize-request',
metavar='RESIZE_REQUEST_NAME',
type=str,
required=True,
help="""The name of the resize request to describe.""")
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.get request."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
igm_ref = self._GetIgmRef(args, holder, resource_arg)
return self._MakeRequest(args, holder, igm_ref)
@classmethod
def _GetIgmRef(cls, args, holder, resource_arg):
return resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(holder.client),
)
@classmethod
def _MakeRequest(cls, args, holder, igm_ref):
client = holder.client
if igm_ref.Collection() == 'compute.instanceGroupManagers':
requests = [(
client.apitools_client.instanceGroupManagerResizeRequests,
'Get',
client.messages.ComputeInstanceGroupManagerResizeRequestsGetRequest(
project=igm_ref.project,
zone=igm_ref.zone,
instanceGroupManager=igm_ref.instanceGroupManager,
resizeRequest=args.resize_request,
),
)]
return client.MakeRequests(requests)[0]
if igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
requests = [(
client.apitools_client.regionInstanceGroupManagerResizeRequests,
'Get',
client.messages.ComputeRegionInstanceGroupManagerResizeRequestsGetRequest(
project=igm_ref.project,
region=igm_ref.region,
instanceGroupManager=igm_ref.instanceGroupManager,
resizeRequest=args.resize_request,
),
)]
return client.MakeRequests(requests)[0]
else:
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)

View File

@@ -0,0 +1,161 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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 for listing managed instance group resize requests."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import request_helper
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed.resize_requests import flags as rr_flags
DETAILED_HELP = {
'DESCRIPTION':
"""\
{command} displays all Compute Engine resize requests in a managed
instance group.
""",
'EXAMPLES':
"""\
To list all resize requests in a managed instance group in table form,
run:
$ {command} example-managed-instance-group --zone=us-central1-a
To list the URIs of all resize requests in a managed instance group, run:
$ {command} example-managed-instance-group --zone=us-central1-a --uri
"""
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class List(base.ListCommand):
"""List Compute Engine managed instance group resize requests."""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
rr_flags.AddOutputFormat(parser, base.ReleaseTrack.GA)
instance_groups_flags.MakeZonalInstanceGroupManagerArg().AddArgument(
parser)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.list request.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
List of resize requests.
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MakeZonalInstanceGroupManagerArg()
igm_ref = self._GetIgmRef(args, holder, resource_arg)
return self._Run(holder.client, igm_ref)
def _GetIgmRef(self, args, holder, resource_arg):
return resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(holder.client),
)
def _Run(self, client, igm_ref):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagerResizeRequests
request = (
client.messages.ComputeInstanceGroupManagerResizeRequestsListRequest(
instanceGroupManager=igm_ref.Name(),
zone=igm_ref.zone,
project=igm_ref.project,
)
)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.apitools_client.regionInstanceGroupManagerResizeRequests
request = client.messages.ComputeRegionInstanceGroupManagerResizeRequestsListRequest(
instanceGroupManager=igm_ref.Name(),
region=igm_ref.region,
project=igm_ref.project,
)
else:
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
errors = []
results = list(request_helper.MakeRequests(
requests=[(service, 'List', request)],
http=client.apitools_client.http,
batch_url=client.batch_url,
errors=errors))
if errors:
utils.RaiseToolException(errors)
return results
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class ListBeta(List):
"""List Compute Engine managed instance group resize requests."""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
rr_flags.AddOutputFormat(parser, base.ReleaseTrack.BETA)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
"""Creates and issues an instanceGroupManagerResizeRequests.list request."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
igm_ref = self._GetIgmRef(args, holder, resource_arg)
return self._Run(holder.client, igm_ref)
def _GetIgmRef(self, args, holder, resource_arg):
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(holder.client),
)
return igm_ref
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ListAlpha(ListBeta):
"""List Compute Engine managed instance group resize requests."""
detailed_help = DETAILED_HELP
@classmethod
def Args(cls, parser):
rr_flags.AddOutputFormat(parser, base.ReleaseTrack.ALPHA)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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 for resuming instances owned by a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class ResumeInstances(base.Command):
"""Resume instances owned by a managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(project(),
zone(),
instanceName:label=INSTANCE,
status)""")
parser.add_argument('--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
required=True,
help='Names of instances to resume.')
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instances_holder_field = 'instanceGroupManagersResumeInstancesRequest'
request = client.messages.ComputeInstanceGroupManagersResumeInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersResumeInstancesRequest=client.messages
.InstanceGroupManagersResumeInstancesRequest(instances=[]),
project=igm_ref.project,
zone=igm_ref.zone)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instances_holder_field = 'regionInstanceGroupManagersResumeInstancesRequest'
request = client.messages.ComputeRegionInstanceGroupManagersResumeInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersResumeInstancesRequest=client.messages
.RegionInstanceGroupManagersResumeInstancesRequest(instances=[]),
project=igm_ref.project,
region=igm_ref.region,
)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='ResumeInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances)
ResumeInstances.detailed_help = {
'brief': 'Resume the suspended instances in a managed instance group.',
'DESCRIPTION': """
*{command}* resumes one or more instances from a managed instance group,
thereby increasing the targetSize and reducing the targetSuspendedSize of the
group.
The command returns the operation status per instance, which might be ``FAIL'',
``SUCCESS'', or ``MEMBER_NOT_FOUND''. ``MEMBER_NOT_FOUND'' is returned only for
regional groups when the gcloud command-line tool wasn't able to resolve the
zone from the instance name.
""",
'EXAMPLES': """\
To resume an instance from a managed instance group in the us-central1-a
zone, run:
$ {command} example-managed-instance-group --zone=us-central1-a \\
--instances=example-instance
""",
}

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 reading and manipulating managed instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
base.ReleaseTrack.GA)
class ManagedInstanceGroupsRollingAction(base.Group):
"""Read and manipulate Compute Engine managed instance groups."""
ManagedInstanceGroupsRollingAction.detailed_help = {
'brief': (
'Manipulate rolling actions on Compute Engine managed instance '
'groups'),
}

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for replacing instances of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as instance_groups_managed_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import rolling_action
from googlecloudsdk.command_lib.compute.managed_instance_groups import update_instances_utils
def _AddArgs(parser, supports_min_ready=False):
"""Adds args."""
instance_groups_managed_flags.AddMaxSurgeArg(parser)
instance_groups_managed_flags.AddMaxUnavailableArg(parser)
if supports_min_ready:
instance_groups_managed_flags.AddMinReadyArg(parser)
instance_groups_managed_flags.AddReplacementMethodFlag(parser)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class StartUpdate(base.Command):
"""Replaces instances in a managed instance group.
Deletes the existing instance and creates a new instance from the target
template. The Updater creates a brand new instance with all new instance
properties, such as new internal and external IP addresses.
"""
@staticmethod
def Args(parser):
_AddArgs(parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
minimal_action = (client.messages.InstanceGroupManagerUpdatePolicy.
MinimalActionValueValuesEnum.REPLACE)
max_surge = update_instances_utils.ParseFixedOrPercent(
'--max-surge', 'max-surge', args.max_surge, client.messages)
return client.MakeRequests([
rolling_action.CreateRequest(args, client, resources,
minimal_action, max_surge)
])
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class StartUpdateBeta(StartUpdate):
"""Replaces instances in a managed instance group.
Deletes the existing instance and creates a new instance from the target
template. The Updater creates a brand new instance with all new instance
properties, such as new internal and external IP addresses.
"""
@staticmethod
def Args(parser):
_AddArgs(parser, supports_min_ready=True)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)

View File

@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for restarting instances of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as instance_groups_managed_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import rolling_action
def _AddArgs(parser, supports_min_ready=False):
"""Adds args."""
instance_groups_managed_flags.AddMaxUnavailableArg(parser)
if supports_min_ready:
instance_groups_managed_flags.AddMinReadyArg(parser)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class StartUpdate(base.Command):
"""Start restart instances of managed instance group."""
@staticmethod
def Args(parser):
_AddArgs(parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resources = holder.resources
minimal_action = (client.messages.InstanceGroupManagerUpdatePolicy.
MinimalActionValueValuesEnum.RESTART)
return client.MakeRequests([
rolling_action.CreateRequest(args, client, resources, minimal_action)
])
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class StartUpdateAlphaBeta(StartUpdate):
"""Start restart instances of managed instance group."""
@staticmethod
def Args(parser):
_AddArgs(parser, supports_min_ready=True)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
StartUpdate.detailed_help = {
'brief':
'Restarts instances in a managed instance group',
'DESCRIPTION':
"""\
*{command}* restarts instances in a managed instance group, effectively
performing a stop and start request. Note, if your request
requires that the instance be replaced to pick up changes, a forced
`replace` will be performed instead."""
}

View File

@@ -0,0 +1,243 @@
# -*- coding: utf-8 -*- #
# Copyright 2016 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 for updating instances of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as instance_groups_managed_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import rolling_action
from googlecloudsdk.command_lib.compute.managed_instance_groups import update_instances_utils
TEMPLATE_NAME_KEY = 'template'
def _AddArgs(parser, supports_min_ready=False):
"""Adds args."""
instance_groups_managed_flags.AddTypeArg(parser)
instance_groups_managed_flags.AddMaxSurgeArg(parser)
instance_groups_managed_flags.AddMaxUnavailableArg(parser)
if supports_min_ready:
instance_groups_managed_flags.AddMinReadyArg(parser)
instance_groups_managed_flags.AddReplacementMethodFlag(parser)
parser.add_argument(
'--version',
type=arg_parsers.ArgDict(spec={'template': str,
'name': str}),
metavar='template=TEMPLATE,[name=NAME]',
help=('Original instance template resource to be used. '
'Each version has the following format: '
'template=TEMPLATE,[name=NAME]'),
required=True)
parser.add_argument(
'--canary-version',
type=arg_parsers.ArgDict(
spec={'template': str,
'target-size': str,
'name': str}),
category=base.COMMONLY_USED_FLAGS,
metavar='template=TEMPLATE,target-size=FIXED_OR_PERCENT,[name=NAME]',
help=('New instance template resource to be used. '
'Each version has the following format: '
'template=TEMPLATE,target-size=FIXED_OR_PERCENT,[name=NAME]'))
instance_groups_managed_flags.AddForceArg(parser)
instance_groups_managed_flags.AddMinimalActionArg(parser, False, None)
instance_groups_managed_flags.AddMostDisruptiveActionArg(parser, False, None)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class StartUpdateGA(base.Command):
"""Start update instances of managed instance group."""
@classmethod
def Args(cls, parser):
_AddArgs(parser=parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
update_instances_utils.ValidateCanaryVersionFlag('--canary-version',
args.canary_version)
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
request = self.CreateRequest(args, client, holder.resources)
return client.MakeRequests([request])
def CreateRequest(self, args, client, resources):
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args, resources, default_scope=default_scope, scope_lister=scope_lister)
if igm_ref.Collection() not in [
'compute.instanceGroupManagers', 'compute.regionInstanceGroupManagers'
]:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
update_policy_type = update_instances_utils.ParseUpdatePolicyType(
'--type', args.type, client.messages)
max_surge = update_instances_utils.ParseFixedOrPercent(
'--max-surge', 'max-surge', args.max_surge, client.messages)
max_unavailable = update_instances_utils.ParseFixedOrPercent(
'--max-unavailable', 'max-unavailable', args.max_unavailable,
client.messages)
igm_info = managed_instance_groups_utils.GetInstanceGroupManagerOrThrow(
igm_ref, client)
# Value of instance template's name in args.version is a string, so we add
# it as a separate argument args.template, which will be parsed as a
# ResourceArgument that will make parsing regional instance templates
# possible.
if TEMPLATE_NAME_KEY in args.version:
args.template = args.version[TEMPLATE_NAME_KEY]
versions = []
versions.append(
update_instances_utils.ParseVersion(
args,
'--version',
args.version,
resources,
client.messages,
)
)
if args.canary_version:
if TEMPLATE_NAME_KEY in args.canary_version:
args.template = args.canary_version[TEMPLATE_NAME_KEY]
versions.append(
update_instances_utils.ParseVersion(
args,
'--canary-version',
args.canary_version,
resources,
client.messages,
)
)
managed_instance_groups_utils.ValidateVersions(igm_info, versions,
resources, args.force)
# TODO(b/36049787): Decide what we should do when two versions have the same
# instance template (this can happen with canary restart
# performed using tags).
igm_version_names = {
version.instanceTemplate: version.name
for version in igm_info.versions
}
for version in versions:
if not version.name:
version.name = igm_version_names.get(version.instanceTemplate)
update_policy = client.messages.InstanceGroupManagerUpdatePolicy(
maxSurge=max_surge,
maxUnavailable=max_unavailable,
type=update_policy_type)
if args.IsSpecified('minimal_action'):
update_policy.minimalAction = (
update_instances_utils.ParseInstanceActionFlag)(
'--minimal-action', args.minimal_action,
client.messages.InstanceGroupManagerUpdatePolicy
.MinimalActionValueValuesEnum)
if args.IsSpecified('most_disruptive_allowed_action'):
update_policy.mostDisruptiveAllowedAction = (
update_instances_utils.ParseInstanceActionFlag)(
'--most-disruptive-allowed-action',
args.most_disruptive_allowed_action,
client.messages.InstanceGroupManagerUpdatePolicy
.MostDisruptiveAllowedActionValueValuesEnum)
# min_ready is available in alpha and beta APIs only
if hasattr(args, 'min_ready'):
update_policy.minReadySec = args.min_ready
# replacement_method is available in alpha API only
if hasattr(args, 'replacement_method'):
replacement_method = update_instances_utils.ParseReplacementMethod(
args.replacement_method, client.messages)
update_policy.replacementMethod = replacement_method
rolling_action.ValidateAndFixUpdaterAgainstStateful(
update_policy, igm_info, client, args
)
igm_resource = client.messages.InstanceGroupManager(
instanceTemplate=None, updatePolicy=update_policy, versions=versions)
if hasattr(igm_ref, 'zone'):
service = client.apitools_client.instanceGroupManagers
request = (client.messages.ComputeInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_resource,
project=igm_ref.project,
zone=igm_ref.zone))
elif hasattr(igm_ref, 'region'):
service = client.apitools_client.regionInstanceGroupManagers
request = (client.messages.ComputeRegionInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_resource,
project=igm_ref.project,
region=igm_ref.region))
return service, 'Patch', request
StartUpdateGA.detailed_help = {
'brief': 'Updates instances in a managed instance group',
'DESCRIPTION': """\
*{command}* updates instances in a managed instance group,
according to the given versions and the given update policy.
An instance template version can be either a global or regional resource.
""",
'EXAMPLES': """
Running:
{command} example-managed-instance-group \\
--version='template=example-global-instance-template'
Sets the group's instance template version to a global instance template
resource 'example-global-instance-template'.
To use a regional instance template, specify the full or partial URL of the template.
Running:
{command} example-managed-instance-group \\
--version='template=projects/example-project/regions/us-central1/instanceTemplates/example-regional-instance-template'
Sets the group's instance template version to a regional instance template
resource 'example-regional-instance-template'.
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class StartUpdate(StartUpdateGA):
"""Start update instances of managed instance group."""
@classmethod
def Args(cls, parser):
_AddArgs(parser=parser, supports_min_ready=True)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser
)
StartUpdate.detailed_help = StartUpdateGA.detailed_help

View File

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for stopping the update process of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
base.ReleaseTrack.GA)
class StopProactiveUpdate(base.Command):
"""Stop the proactive update process of managed instance group.
This command changes the update type of the managed instance group to
opportunistic.
"""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
messages = client.messages
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
igm_resource = messages.InstanceGroupManager(
updatePolicy=messages.InstanceGroupManagerUpdatePolicy(
type=(messages.InstanceGroupManagerUpdatePolicy.
TypeValueValuesEnum.OPPORTUNISTIC)))
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request_type = messages.ComputeInstanceGroupManagersPatchRequest
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.apitools_client.regionInstanceGroupManagers
request_type = messages.ComputeRegionInstanceGroupManagersPatchRequest
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
request = request_type(**igm_ref.AsDict())
request.instanceGroupManagerResource = igm_resource
return client.MakeRequests([(service, 'Patch', request)])

View File

@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for setting autohealing policy of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.managed_instance_groups import auto_healing_utils
@base.Deprecate(
is_removed=False,
warning=('This command is deprecated and will not be promoted to GA. '
'Please use `gcloud beta instance-groups managed update` instead.')
)
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class SetAutohealing(base.Command):
"""Set autohealing policy for managed instance group.
*{command}* updates the autohealing policy for an existing managed
instance group.
If health check is specified, the resulting autohealing policy will be
triggered by the health-check signal i.e. the autohealing action (RECREATE) on
an instance will be performed if the health-check signals that the instance is
UNHEALTHY. If no health check is specified, the resulting autohealing policy
will be triggered by instance's status i.e. the autohealing action (RECREATE)
on an instance will be performed if the instance.status is not RUNNING.
"""
@classmethod
def Args(cls, parser):
auto_healing_utils.AddAutohealingArgs(parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
messages = client.messages
health_check = managed_instance_groups_utils.GetHealthCheckUri(
holder.resources, args)
auto_healing_policies = (
managed_instance_groups_utils.CreateAutohealingPolicies(
client.messages, health_check, args.initial_delay))
managed_instance_groups_utils.ValidateAutohealingPolicies(
auto_healing_policies)
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
igm_resource = messages.InstanceGroupManager(
autoHealingPolicies=auto_healing_policies)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request_type = messages.ComputeInstanceGroupManagersPatchRequest
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.apitools_client.regionInstanceGroupManagers
request_type = messages.ComputeRegionInstanceGroupManagersPatchRequest
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
request = request_type(**igm_ref.AsDict())
request.instanceGroupManagerResource = igm_resource
return client.MakeRequests([(service, 'Patch', request)])

View File

@@ -0,0 +1,270 @@
# -*- 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 for configuring autoscaling of a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import json
import re
from apitools.base.py import encoding
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute.instance_groups.managed import autoscalers as autoscalers_api
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
from googlecloudsdk.core.util import files
_DELETE_AUTOSCALER_PROMPT = (
'Configuration specifies no autoscaling configuration. '
'Continuing will delete the existing autoscaler '
'configuration.')
_REPLACE_AUTOSCALER_PROMPT = (
'Configuration specifies autoscaling configuration with a '
'different name than existing. Continuing will delete '
'existing autoscaler and create new one with a different name.')
_DELETION_CANCEL_STRING = 'Deletion aborted by user.'
@base.ReleaseTracks(base.ReleaseTrack.GA)
class SetAutoscaling(base.Command):
"""Set autoscaling parameters of a managed instance group."""
@staticmethod
def Args(parser):
managed_instance_groups_utils.AddAutoscalerArgs(parser=parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
managed_instance_groups_utils.AddPredictiveAutoscaling(parser,
standard=False)
def CreateAutoscalerResource(self,
client,
resources,
igm_ref,
args):
autoscaler = managed_instance_groups_utils.AutoscalerForMigByRef(
client, resources, igm_ref)
autoscaler_name = getattr(autoscaler, 'name', None)
new_one = managed_instance_groups_utils.IsAutoscalerNew(autoscaler)
autoscaler_name = autoscaler_name or args.name
autoscaler_resource = managed_instance_groups_utils.BuildAutoscaler(
args,
client.messages,
igm_ref,
autoscaler_name,
autoscaler)
return autoscaler_resource, new_one
def _SetAutoscalerFromFile(
self, autoscaling_file, autoscalers_client, igm_ref,
existing_autoscaler_name):
new_autoscaler = json.loads(files.ReadFileContents(autoscaling_file))
if new_autoscaler is None:
if existing_autoscaler_name is None:
log.info('Configuration specifies no autoscaling and there is no '
'autoscaling configured. Nothing to do.')
return
else:
console_io.PromptContinue(
message=_DELETE_AUTOSCALER_PROMPT, cancel_on_no=True,
cancel_string=_DELETION_CANCEL_STRING)
return autoscalers_client.Delete(igm_ref, existing_autoscaler_name)
new_autoscaler = encoding.DictToMessage(new_autoscaler,
autoscalers_client.message_type)
if existing_autoscaler_name is None:
managed_instance_groups_utils.AdjustAutoscalerNameForCreation(
new_autoscaler, igm_ref)
return autoscalers_client.Insert(igm_ref, new_autoscaler)
if (getattr(new_autoscaler, 'name', None) and
getattr(new_autoscaler, 'name') != existing_autoscaler_name):
console_io.PromptContinue(
message=_REPLACE_AUTOSCALER_PROMPT, cancel_on_no=True,
cancel_string=_DELETION_CANCEL_STRING)
autoscalers_client.Delete(igm_ref, existing_autoscaler_name)
return autoscalers_client.Insert(igm_ref, new_autoscaler)
new_autoscaler.name = existing_autoscaler_name
return autoscalers_client.Update(igm_ref, new_autoscaler)
def _PromptToAutoscaleGKENodeGroup(self, args):
prompt_message = (
'You should not use Compute Engine\'s autoscaling feature '
'on instance groups created by Kubernetes Engine.')
if re.match(r'^gke-.*-[0-9a-f]{1,8}-grp$', args.name):
console_io.PromptContinue(
message=prompt_message, default=False, cancel_on_no=True,
cancel_string='Setting autoscaling aborted by user.')
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
managed_instance_groups_utils.ValidateAutoscalerArgs(args)
managed_instance_groups_utils.ValidateStackdriverMetricsFlags(args)
igm_ref = instance_groups_flags.CreateGroupReference(
client, holder.resources, args)
# Assert that Instance Group Manager exists.
managed_instance_groups_utils.GetInstanceGroupManagerOrThrow(
igm_ref, client)
# Require confirmation if autoscaling a GKE node group.
self._PromptToAutoscaleGKENodeGroup(args)
autoscaler_resource, is_new = self.CreateAutoscalerResource(
client, holder.resources, igm_ref, args)
managed_instance_groups_utils.ValidateGeneratedAutoscalerIsValid(
args, autoscaler_resource)
autoscalers_client = autoscalers_api.GetClient(client, igm_ref)
if is_new:
managed_instance_groups_utils.AdjustAutoscalerNameForCreation(
autoscaler_resource, igm_ref)
return autoscalers_client.Insert(igm_ref, autoscaler_resource)
return autoscalers_client.Update(igm_ref, autoscaler_resource)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class SetAutoscalingBeta(SetAutoscaling):
"""Set autoscaling parameters of a managed instance group."""
@staticmethod
def Args(parser):
managed_instance_groups_utils.AddAutoscalerArgs(
parser=parser,
autoscaling_file_enabled=True,
patch_args=False)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
managed_instance_groups_utils.AddPredictiveAutoscaling(parser,
standard=False)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
managed_instance_groups_utils.ValidateAutoscalerArgs(args)
managed_instance_groups_utils.ValidateStackdriverMetricsFlags(args)
managed_instance_groups_utils.ValidateConflictsWithAutoscalingFile(
args,
(managed_instance_groups_utils.
ARGS_CONFLICTING_WITH_AUTOSCALING_FILE_BETA))
igm_ref = instance_groups_flags.CreateGroupReference(
client, holder.resources, args)
# Assert that Instance Group Manager exists.
managed_instance_groups_utils.GetInstanceGroupManagerOrThrow(
igm_ref, client)
autoscaler_resource, is_new = self.CreateAutoscalerResource(
client, holder.resources, igm_ref, args)
managed_instance_groups_utils.ValidateGeneratedAutoscalerIsValid(
args, autoscaler_resource)
autoscalers_client = autoscalers_api.GetClient(client, igm_ref)
if args.IsSpecified('autoscaling_file'):
if is_new:
existing_autoscaler_name = None
else:
existing_autoscaler_name = autoscaler_resource.name
return self._SetAutoscalerFromFile(
args.autoscaling_file, autoscalers_client, igm_ref,
existing_autoscaler_name)
if is_new:
managed_instance_groups_utils.AdjustAutoscalerNameForCreation(
autoscaler_resource, igm_ref)
return autoscalers_client.Insert(igm_ref, autoscaler_resource)
return autoscalers_client.Update(igm_ref, autoscaler_resource)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class SetAutoscalingAlpha(SetAutoscaling):
"""Set autoscaling parameters of a managed instance group."""
@staticmethod
def Args(parser):
managed_instance_groups_utils.AddAutoscalerArgs(
parser=parser,
autoscaling_file_enabled=True,
patch_args=False)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
managed_instance_groups_utils.AddPredictiveAutoscaling(parser,
standard=True)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
managed_instance_groups_utils.ValidateAutoscalerArgs(args)
managed_instance_groups_utils.ValidateStackdriverMetricsFlags(args)
managed_instance_groups_utils.ValidateConflictsWithAutoscalingFile(
args,
(managed_instance_groups_utils.
ARGS_CONFLICTING_WITH_AUTOSCALING_FILE_ALPHA))
igm_ref = instance_groups_flags.CreateGroupReference(
client, holder.resources, args)
# Assert that Instance Group Manager exists.
managed_instance_groups_utils.GetInstanceGroupManagerOrThrow(
igm_ref, client)
autoscaler_resource, is_new = self.CreateAutoscalerResource(
client,
holder.resources,
igm_ref,
args)
managed_instance_groups_utils.ValidateGeneratedAutoscalerIsValid(
args, autoscaler_resource)
autoscalers_client = autoscalers_api.GetClient(client, igm_ref)
if args.IsSpecified('autoscaling_file'):
if is_new:
existing_autoscaler_name = None
else:
existing_autoscaler_name = autoscaler_resource.name
return self._SetAutoscalerFromFile(
args.autoscaling_file, autoscalers_client, igm_ref,
existing_autoscaler_name)
if is_new:
managed_instance_groups_utils.AdjustAutoscalerNameForCreation(
autoscaler_resource, igm_ref)
return autoscalers_client.Insert(igm_ref, autoscaler_resource)
return autoscalers_client.Update(igm_ref, autoscaler_resource)
SetAutoscaling.detailed_help = {
'brief': 'Set autoscaling parameters of a managed instance group',
'DESCRIPTION': """
*{command}* sets autoscaling parameters of specified managed instance
group.
Autoscalers can use one or more autoscaling signals. Information on using
multiple autoscaling signals can be found here: [](https://cloud.google.com/compute/docs/autoscaler/multiple-signals)
""",
}
SetAutoscalingAlpha.detailed_help = SetAutoscaling.detailed_help
SetAutoscalingBeta.detailed_help = SetAutoscaling.detailed_help

View File

@@ -0,0 +1,142 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for setting instance template of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as managed_flags
@base.ReleaseTracks(base.ReleaseTrack.GA)
class SetInstanceTemplateGA(base.Command):
r"""Command for setting instance template of managed instance group."""
@classmethod
def Args(cls, parser):
managed_flags.INSTANCE_TEMPLATE_ARG.AddArgument(parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
template_ref = managed_flags.INSTANCE_TEMPLATE_ARG.ResolveAsResource(
args,
holder.resources,
default_scope=flags.compute_scope.ScopeEnum.GLOBAL,
)
return self._MakePatchRequest(client, igm_ref, template_ref)
def _MakePatchRequest(self, client, igm_ref, template_ref):
messages = client.messages
igm_resource = messages.InstanceGroupManager(
instanceTemplate=template_ref.SelfLink(),
versions=[
messages.InstanceGroupManagerVersion(
instanceTemplate=template_ref.SelfLink())
])
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request_type = messages.ComputeInstanceGroupManagersPatchRequest
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.apitools_client.regionInstanceGroupManagers
request_type = messages.ComputeRegionInstanceGroupManagersPatchRequest
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
request = request_type(**igm_ref.AsDict())
request.instanceGroupManagerResource = igm_resource
return client.MakeRequests([(service, 'Patch', request)])
SetInstanceTemplateGA.detailed_help = {
'brief': 'Set the instance template for a managed instance group.',
'DESCRIPTION': """
*{command}* sets the instance template for an existing managed instance
group.
The new template applies to all new instances added to the managed instance
group.
To apply the new template to existing instances in the group, use one of the
following methods:
- Update instances using the `update-instances` command.
- Recreate instances using the `recreate-instances` command.
- Use the `rolling-action start-update` command.
- Use the API to set the group's `updatePolicy.type` to `PROACTIVE`.
""",
'EXAMPLES': """
Running:
{command} \\
example-managed-instance-group --template=example-global-instance-template
Sets the instance template for the 'example-managed-instance-group' group
to a global resource 'example-global-instance-template'.
To use a regional instance template, specify the full or partial URL of the template.
Running:
{command} \\
example-managed-instance-group \\
--template=projects/example-project/regions/us-central1/instanceTemplates/example-regional-instance-template
Sets the instance template for the 'example-managed-instance-group' group
to a regional resource 'example-regional-instance-template'.
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class SetInstanceTemplate(SetInstanceTemplateGA):
r"""Command for setting instance template of managed instance group."""
@classmethod
def Args(cls, parser):
super(SetInstanceTemplate, cls).Args(parser)
def Run(self, args):
patch_request = super(SetInstanceTemplate, self).Run(args)
return patch_request
SetInstanceTemplate.detailed_help = SetInstanceTemplateGA.detailed_help

View File

@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""instance-groups managed set-named-ports command.
It's an alias for the instance-groups set-named-ports command.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags
class SetNamedPortsAlpha(base.SilentCommand):
"""Sets named ports for instance groups."""
@staticmethod
def Args(parser):
flags.AddNamedPortsArgs(parser)
flags.MULTISCOPE_INSTANCE_GROUP_ARG.AddArgument(parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = flags.MULTISCOPE_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources, default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=compute_flags.GetDefaultScopeLister(client))
ports = instance_groups_utils.ValidateAndParseNamedPortsArgs(
client.messages, args.named_ports)
# service could be zonal or regional
request, service = instance_groups_utils.GetSetNamedPortsRequestForGroup(
client, group_ref, ports)
return client.MakeRequests([(service, 'SetNamedPorts', request)])
detailed_help = instance_groups_utils.SET_NAMED_PORTS_HELP

View File

@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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 for setting instance template of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.managed_instance_groups import standby_policy_utils
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class SetStandbyPolicyAlpha(base.Command):
r"""Set the standby policy for a managed instance group.
*{command}* sets the fields in the standby policy for a managed instance
group. The standby policy dictates the behaviour of standby (stopped and
suspended) instances
"""
@staticmethod
def Args(parser):
standby_policy_utils.AddStandbyPolicyArgs(parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
initial_delay_sec = args.initial_delay or None
standby_policy = managed_instance_groups_utils.CreateStandbyPolicy(
client.messages, initial_delay_sec=initial_delay_sec
)
if not standby_policy:
return
return self._MakePatchRequest(client, igm_ref, standby_policy)
def _MakePatchRequest(self, client, igm_ref, standby_policy):
messages = client.messages
igm_resource = messages.InstanceGroupManager(standbyPolicy=standby_policy)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request_type = messages.ComputeInstanceGroupManagersPatchRequest
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
service = client.apitools_client.regionInstanceGroupManagers
request_type = messages.ComputeRegionInstanceGroupManagersPatchRequest
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
request = request_type(**igm_ref.AsDict())
request.instanceGroupManagerResource = igm_resource
return client.MakeRequests([(service, 'Patch', request)])

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for setting target pools of managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
def _AddArgs(parser):
"""Add args."""
parser.add_argument(
'--target-pools',
required=True,
type=arg_parsers.ArgList(min_length=0),
metavar='TARGET_POOL',
help=('Compute Engine Target Pools to add the instances to. '
'Target Pools must be specified by name or by URL. Example: '
'--target-pools=target-pool-1,target-pool-2. To clear the set of '
'Target Pools pass in an empty list. Example: --target-pools=""'))
class SetTargetPools(base.Command):
"""Set target pools of managed instance group.
*{command}* sets the target pools for an existing managed instance group.
Instances that are part of the managed instance group will be added to the
target pool automatically.
"""
@staticmethod
def Args(parser):
_AddArgs(parser=parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
region = self._GetRegionName(igm_ref)
pool_refs = []
for target_pool in args.target_pools:
pool_refs.append(
holder.resources.Parse(
target_pool,
params={
'project': igm_ref.project,
'region': region
},
collection='compute.targetPools'))
pools = [pool_ref.SelfLink() for pool_ref in pool_refs]
if pools:
return self._MakePatchRequest(client, igm_ref, pools)
else:
# Forces apitools to include field even when it is an empty list.
with client.apitools_client.IncludeFields(['targetPools']):
return self._MakePatchRequest(client, igm_ref, pools)
def _GetRegionName(self, igm_ref):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
return utils.ZoneNameToRegionName(igm_ref.zone)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
return igm_ref.region
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
def _MakePatchRequest(self, client, igm_ref, pools):
messages = client.messages
igm_resource = messages.InstanceGroupManager(targetPools=pools)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request_type = messages.ComputeInstanceGroupManagersPatchRequest
else:
service = client.apitools_client.regionInstanceGroupManagers
request_type = messages.ComputeRegionInstanceGroupManagersPatchRequest
request = request_type(**igm_ref.AsDict())
request.instanceGroupManagerResource = igm_resource
return client.MakeRequests([(service, 'Patch', request)])

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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 for starting instances owned by a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class StartInstances(base.Command):
"""Start instances owned by a managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(project(),
zone(),
instanceName:label=INSTANCE,
status)""")
parser.add_argument('--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
required=True,
help='Names of instances to start.')
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instances_holder_field = 'instanceGroupManagersStartInstancesRequest'
request = client.messages.ComputeInstanceGroupManagersStartInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersStartInstancesRequest=client.messages
.InstanceGroupManagersStartInstancesRequest(instances=[]),
project=igm_ref.project,
zone=igm_ref.zone)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instances_holder_field = 'regionInstanceGroupManagersStartInstancesRequest'
request = client.messages.ComputeRegionInstanceGroupManagersStartInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersStartInstancesRequest=client.messages
.RegionInstanceGroupManagersStartInstancesRequest(instances=[]),
project=igm_ref.project,
region=igm_ref.region,
)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='StartInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances)
StartInstances.detailed_help = {
'brief': 'Start the stopped instances in a managed instance group.',
'DESCRIPTION': """
*{command}* starts one or more instances from a managed instance group,
thereby increasing the targetSize and reducing the targetStoppedSize of the
group.
The command returns the operation status per instance, which might be ``FAIL'',
``SUCCESS'', or ``MEMBER_NOT_FOUND''. ``MEMBER_NOT_FOUND'' is returned only for
regional groups when the gcloud command-line tool wasn't able to resolve the
zone from the instance name.
""",
'EXAMPLES': """\
To start an instance from a managed instance group in the us-central1-a
zone, run:
$ {command} example-managed-instance-group --zone=us-central1-a \\
--instances=example-instance
""",
}

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for stopping autoscaling of a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
def _IsZonalGroup(ref):
"""Checks if reference to instance group is zonal."""
return ref.Collection() == 'compute.instanceGroupManagers'
class StopAutoscaling(base.Command):
"""Stop autoscaling a managed instance group.
*{command}* stops autoscaling a managed instance group and deletes the
autoscaler configuration. If autoscaling is not enabled for the managed
instance group, this command does nothing and will report an error.
If you need to keep the autoscaler configuration, you can temporarily disable
an autoscaler by setting its `mode` to `off` using the ``update-autoscaling''
command instead.
"""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def CreateGroupReference(self, client, resources, args):
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
return resource_arg.ResolveAsResource(
args, resources, default_scope=default_scope,
scope_lister=scope_lister)
def GetAutoscalerServiceForGroup(self, client, group_ref):
if _IsZonalGroup(group_ref):
return client.apitools_client.autoscalers
else:
return client.apitools_client.regionAutoscalers
def ScopeRequest(self, request, igm_ref):
if _IsZonalGroup(igm_ref):
request.zone = igm_ref.zone
else:
request.region = igm_ref.region
def GetAutoscalerResource(self, client, resources, igm_ref, args):
if _IsZonalGroup(igm_ref):
scope_type = 'zone'
location = managed_instance_groups_utils.CreateZoneRef(
resources, igm_ref)
zones, regions = [location], None
else:
scope_type = 'region'
location = managed_instance_groups_utils.CreateRegionRef(
resources, igm_ref)
zones, regions = None, [location]
autoscaler = managed_instance_groups_utils.AutoscalerForMig(
mig_name=args.name,
autoscalers=managed_instance_groups_utils.AutoscalersForLocations(
regions=regions,
zones=zones,
client=client),
location=location,
scope_type=scope_type)
if autoscaler is None:
raise managed_instance_groups_utils.ResourceNotFoundException(
'The managed instance group is not autoscaled.')
return autoscaler
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = self.CreateGroupReference(client, holder.resources, args)
service = self.GetAutoscalerServiceForGroup(client, igm_ref)
# Assert that Instance Group Manager exists.
managed_instance_groups_utils.GetInstanceGroupManagerOrThrow(
igm_ref, client)
autoscaler = self.GetAutoscalerResource(client, holder.resources, igm_ref,
args)
request = service.GetRequestType('Delete')(
project=igm_ref.project,
autoscaler=autoscaler.name)
self.ScopeRequest(request, igm_ref)
return client.MakeRequests([(service, 'Delete', request)])

View File

@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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 for stoping instances owned by a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class StopInstances(base.Command):
"""Stop instances owned by a managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(project(),
zone(),
instanceName:label=INSTANCE,
status)""")
parser.add_argument('--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
required=True,
help='Names of instances to stop.')
parser.add_argument(
'--force',
default=False,
action='store_true',
help="""
Immediately stop the specified instances, skipping the initial
delay, if one is specified in the standby policy.""")
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instances_holder_field = 'instanceGroupManagersStopInstancesRequest'
request = client.messages.ComputeInstanceGroupManagersStopInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersStopInstancesRequest=client.messages
.InstanceGroupManagersStopInstancesRequest(instances=[]),
project=igm_ref.project,
zone=igm_ref.zone)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instances_holder_field = 'regionInstanceGroupManagersStopInstancesRequest'
request = client.messages.ComputeRegionInstanceGroupManagersStopInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersStopInstancesRequest=client.messages
.RegionInstanceGroupManagersStopInstancesRequest(instances=[]),
project=igm_ref.project,
region=igm_ref.region,
)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
if args.IsSpecified('force'):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
request.instanceGroupManagersStopInstancesRequest.forceStop = args.force
else:
request.regionInstanceGroupManagersStopInstancesRequest.forceStop = args.force
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='StopInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances)
StopInstances.detailed_help = {
'brief': 'Stop instances owned by a managed instance group.',
'DESCRIPTION': """
*{command}* stops one or more instances from a managed instance group
""",
'EXAMPLES': """\
To stop an instance from a managed instance group in the us-central1-a
zone, run:
$ {command} example-managed-instance-group --zone=us-central1-a \\
--instances=example-instance
""",
}

View File

@@ -0,0 +1,127 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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 for suspending instances owned by a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class SuspendInstances(base.Command):
"""Suspend instances owned by a managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(project(),
zone(),
instanceName:label=INSTANCE,
status)""")
parser.add_argument('--instances',
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
required=True,
help='Names of instances to suspend.')
parser.add_argument(
'--force',
default=False,
action='store_true',
help="""
Immediately suspend the specified instances, skipping the initial
delay, if one is specified in the standby policy.""")
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
resource_arg = instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
default_scope = compute_scope.ScopeEnum.ZONE
scope_lister = flags.GetDefaultScopeLister(client)
igm_ref = resource_arg.ResolveAsResource(
args,
holder.resources,
default_scope=default_scope,
scope_lister=scope_lister)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
instances_holder_field = 'instanceGroupManagersSuspendInstancesRequest'
request = client.messages.ComputeInstanceGroupManagersSuspendInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersSuspendInstancesRequest=client.messages
.InstanceGroupManagersSuspendInstancesRequest(instances=[]),
project=igm_ref.project,
zone=igm_ref.zone)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
instances_holder_field = 'regionInstanceGroupManagersSuspendInstancesRequest'
request = client.messages.ComputeRegionInstanceGroupManagersSuspendInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersSuspendInstancesRequest=client.messages
.RegionInstanceGroupManagersSuspendInstancesRequest(instances=[]),
project=igm_ref.project,
region=igm_ref.region,
)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
if args.IsSpecified('force'):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
request.instanceGroupManagersSuspendInstancesRequest.forceSuspend = args.force
else:
request.regionInstanceGroupManagersSuspendInstancesRequest.forceSuspend = args.force
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='SuspendInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances)
SuspendInstances.detailed_help = {
'brief': 'Suspend instances owned by a managed instance group.',
'DESCRIPTION': """
*{command}* suspends one or more instances from a managed instance
group, thereby reducing the targetSize and increasing the targetSuspendedSize
of the group.
The command returns the operation status per instance, which might be ``FAIL'',
``SUCCESS'', or ``MEMBER_NOT_FOUND''. ``MEMBER_NOT_FOUND'' is returned only for
regional groups when the gcloud command-line tool wasn't able to resolve the
zone from the instance name.
""",
'EXAMPLES': """\
To suspend an instance from a managed instance group in the us-central1-a
zone, run:
$ {command} example-managed-instance-group --zone=us-central1-a \\
--instances=example-instance
""",
}

View File

@@ -0,0 +1,542 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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 for updating managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import functools
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.api_lib.compute.instance_groups.managed import stateful_policy_utils as policy_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as managed_flags
from googlecloudsdk.command_lib.compute.managed_instance_groups import auto_healing_utils
from googlecloudsdk.command_lib.util.apis import arg_utils
import six
# Flags valid only for regional MIGs.
REGIONAL_FLAGS = [
'instance_redistribution_type',
'target_distribution_shape',
'on_repair_allow_changing_zone',
]
# TODO(b/345166947) Remove universe annotation once b/341682289 is resolved.
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class UpdateGA(base.UpdateCommand):
r"""Update a Compute Engine managed instance group."""
support_update_policy_min_ready_flag = False
support_multi_mig_flag = False
@classmethod
def Args(cls, parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser, operation_type='update'
)
autohealing_group = parser.add_mutually_exclusive_group()
autohealing_group.add_argument(
'--clear-autohealing',
action='store_true',
default=None,
help="""\
Clears all autohealing policy fields for the managed instance group.
""",
)
autohealing_params_group = autohealing_group.add_group()
auto_healing_utils.AddAutohealingArgs(autohealing_params_group)
instance_groups_flags.AddMigUpdateStatefulFlags(parser)
instance_groups_flags.AddMigUpdateStatefulFlagsIPs(parser)
instance_groups_flags.AddDescriptionFlag(parser, for_update=True)
managed_flags.AddMigInstanceRedistributionTypeFlag(parser)
managed_flags.AddMigDistributionPolicyTargetShapeFlag(parser)
managed_flags.AddMigListManagedInstancesResultsFlag(parser)
managed_flags.AddMigUpdatePolicyFlags(
parser, support_min_ready_flag=cls.support_update_policy_min_ready_flag
)
managed_flags.AddMigForceUpdateOnRepairFlags(parser)
managed_flags.AddMigDefaultActionOnVmFailure(parser, cls.ReleaseTrack())
managed_flags.AddMigSizeFlag(parser)
managed_flags.AddInstanceFlexibilityPolicyArgs(parser, is_update=True)
managed_flags.AddStandbyPolicyFlags(parser)
managed_flags.AddWorkloadPolicyFlags(parser)
if cls.support_multi_mig_flag:
managed_flags.AddMultiMigFlags(parser)
# When adding RMIG-specific flag, update REGIONAL_FLAGS constant.
def _GetUpdatedStatefulPolicyForDisks(
self,
client,
current_stateful_policy,
update_disks=None,
remove_device_names=None,
):
patched_disks_map = {}
if remove_device_names:
managed_instance_groups_utils.RegisterCustomStatefulDisksPatchEncoders(
client
)
else:
# Extract disk protos from current stateful policy proto
if (
current_stateful_policy
and current_stateful_policy.preservedState
and current_stateful_policy.preservedState.disks
):
current_disks = (
current_stateful_policy.preservedState.disks.additionalProperties
)
else:
current_disks = []
# Map of disks to have in the stateful policy, after updating and removing
# the disks specified by the update and remove flags.
patched_disks_map = {
disk_entry.key: disk_entry for disk_entry in current_disks
}
# Update the disks specified in --stateful-disk
for update_disk in update_disks or []:
device_name = update_disk.get('device-name')
updated_preserved_state_disk = (
policy_utils.MakeStatefulPolicyPreservedStateDiskEntry(
client.messages, update_disk
)
)
# Patch semantics on the `--stateful-disk` flag
if device_name in patched_disks_map:
policy_utils.PatchStatefulPolicyDisk(
patched_disks_map[device_name], updated_preserved_state_disk
)
else:
patched_disks_map[device_name] = updated_preserved_state_disk
# Remove the disks specified in --remove-stateful-disks
for device_name in remove_device_names or []:
patched_disks_map[device_name] = (
policy_utils.MakeDiskDeviceNullEntryForDisablingInPatch(
client, device_name
)
)
stateful_disks = sorted(
[
stateful_disk
for _, stateful_disk in six.iteritems(patched_disks_map)
],
key=lambda x: x.key,
)
return stateful_disks
def _GetUpdatedStatefulPolicy(self, client, current_stateful_policy, args):
"""Create an updated stateful policy based on specified args."""
update_disks = args.stateful_disk
remove_device_names = args.remove_stateful_disks
stateful_disks = self._GetUpdatedStatefulPolicyForDisks(
client, current_stateful_policy, update_disks, remove_device_names
)
stateful_policy = policy_utils.MakeStatefulPolicy(
client.messages, stateful_disks
)
stateful_internal_ips = self._GetPatchForStatefulPolicyForInternalIPs(
client, args.stateful_internal_ip, args.remove_stateful_internal_ips
)
stateful_external_ips = self._GetPatchForStatefulPolicyForExternalIPs(
client, args.stateful_external_ip, args.remove_stateful_external_ips
)
return policy_utils.UpdateStatefulPolicy(
client.messages,
stateful_policy,
None,
stateful_internal_ips,
stateful_external_ips,
)
def _StatefulArgsSet(self, args):
return (
args.IsSpecified('stateful_disk')
or args.IsSpecified('remove_stateful_disks')
or args.IsSpecified('stateful_internal_ip')
or args.IsSpecified('remove_stateful_internal_ips')
or args.IsSpecified('stateful_external_ip')
or args.IsSpecified('remove_stateful_external_ips')
)
def _StatefulnessIntroduced(self, args):
return (
args.IsSpecified('stateful_disk')
or args.IsSpecified('stateful_internal_ip')
or args.IsSpecified('stateful_external_ip')
)
def _ValidateStatefulPolicyParams(self, args, stateful_policy):
instance_groups_flags.ValidateUpdateStatefulPolicyParams(
args, stateful_policy
)
instance_groups_flags.ValidateUpdateStatefulPolicyParamsWithIPs(
args, stateful_policy
)
def _GetStatefulPolicyPatchForStatefulIPsCommon(
self,
client,
update_ip_to_ip_entry_lambda,
update_ip_to_none_lambda,
update_ips=None,
remove_interface_names=None,
):
if remove_interface_names:
managed_instance_groups_utils.RegisterCustomStatefulIpsPatchEncoders(
client
)
patched_ips_map = {}
# Update the interfaces specified in IPs to be updated.
for update_ip in update_ips or []:
# Interface name is optional, use the default if not specified.
interface_name = update_ip.get(
'interface-name',
instance_groups_flags.STATEFUL_IP_DEFAULT_INTERFACE_NAME,
)
updated_preserved_state_ip = update_ip_to_ip_entry_lambda(update_ip)
patched_ips_map[interface_name] = updated_preserved_state_ip
# Remove the interfaces specified for removal.
for interface_name in remove_interface_names or []:
updated_preserved_state_ip = update_ip_to_none_lambda(interface_name)
patched_ips_map[interface_name] = updated_preserved_state_ip
stateful_ips = sorted(
[stateful_ip for key, stateful_ip in six.iteritems(patched_ips_map)],
key=lambda x: x.key,
)
return stateful_ips
def _GetPatchForStatefulPolicyForInternalIPs(
self, client, update_internal_ips=None, remove_interface_names=None
):
# Extract internal IPs protos from current stateful policy proto.
return self._GetStatefulPolicyPatchForStatefulIPsCommon(
client,
functools.partial(policy_utils.MakeInternalIPEntry, client.messages),
functools.partial(
policy_utils.MakeInternalIPNullEntryForDisablingInPatch, client
),
update_internal_ips,
remove_interface_names,
)
def _GetPatchForStatefulPolicyForExternalIPs(
self, client, update_external_ips=None, remove_interface_names=None
):
return self._GetStatefulPolicyPatchForStatefulIPsCommon(
client,
functools.partial(policy_utils.MakeExternalIPEntry, client.messages),
functools.partial(
policy_utils.MakeExternalIPNullEntryForDisablingInPatch, client
),
update_external_ips,
remove_interface_names,
)
def _PatchStatefulPolicy(self, igm_patch, args, igm_resource, client, holder):
"""Patch the stateful policy specified in args, to igm_patch."""
# If we're potentially introducing statefulness to the MIG, we should
# validate if this MIG is allowed to be stateful
if self._StatefulnessIntroduced(args):
managed_instance_groups_utils.ValidateIgmReadyForStatefulness(
igm_resource, client
)
self._ValidateStatefulPolicyParams(args, igm_resource.statefulPolicy)
igm_patch.statefulPolicy = self._GetUpdatedStatefulPolicy(
client, igm_resource.statefulPolicy, args
)
return igm_patch
def _GetValidatedAutohealingPolicies(
self, holder, client, args, igm_resource
):
health_check = managed_instance_groups_utils.GetHealthCheckUri(
holder.resources, args
)
auto_healing_policies = (
managed_instance_groups_utils.ModifyAutohealingPolicies(
igm_resource.autoHealingPolicies,
client.messages,
args,
health_check,
)
)
managed_instance_groups_utils.ValidateAutohealingPolicies(
auto_healing_policies
)
return auto_healing_policies
def _PatchTargetDistributionShape(
self,
patch_instance_group_manager,
target_distribution_shape,
igm_resource,
client,
):
distribution_policy = igm_resource.distributionPolicy
if distribution_policy is None:
distribution_policy = client.messages.DistributionPolicy()
distribution_policy.targetShape = arg_utils.ChoiceToEnum(
target_distribution_shape,
client.messages.DistributionPolicy.TargetShapeValueValuesEnum,
)
patch_instance_group_manager.distributionPolicy = distribution_policy
def _MakePatchRequest(self, client, igm_ref, igm_updated_resource):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
service = client.apitools_client.instanceGroupManagers
request = client.messages.ComputeInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_updated_resource,
project=igm_ref.project,
zone=igm_ref.zone,
)
else:
service = client.apitools_client.regionInstanceGroupManagers
request = client.messages.ComputeRegionInstanceGroupManagersPatchRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagerResource=igm_updated_resource,
project=igm_ref.project,
region=igm_ref.region,
)
return client.MakeRequests([(service, 'Patch', request)])
def _GetRegionForGroup(self, igm_ref):
if igm_ref.Collection() == 'compute.instanceGroupManagers':
return utils.ZoneNameToRegionName(igm_ref.zone)
else:
return igm_ref.region
def _CreateInstanceGroupManagerPatch(
self, args, igm_ref, igm_resource, client, holder
):
"""Create IGM resource patch."""
managed_flags.ValidateRegionalMigFlagsUsage(args, REGIONAL_FLAGS, igm_ref)
patch_instance_group_manager = client.messages.InstanceGroupManager()
include_fields = []
auto_healing_policies = self._GetValidatedAutohealingPolicies(
holder, client, args, igm_resource
)
if auto_healing_policies is not None:
patch_instance_group_manager.autoHealingPolicies = auto_healing_policies
update_policy = managed_instance_groups_utils.PatchUpdatePolicy(
client, args, igm_resource.updatePolicy
)
if update_policy is not None:
patch_instance_group_manager.updatePolicy = update_policy
if self._StatefulArgsSet(args):
patch_instance_group_manager = self._PatchStatefulPolicy(
patch_instance_group_manager, args, igm_resource, client, holder
)
if args.target_distribution_shape:
self._PatchTargetDistributionShape(
patch_instance_group_manager,
args.target_distribution_shape,
igm_resource,
client,
)
if args.IsSpecified('description'):
patch_instance_group_manager.description = args.description
if args.IsSpecified('list_managed_instances_results'):
patch_instance_group_manager.listManagedInstancesResults = (
client.messages.InstanceGroupManager.ListManagedInstancesResultsValueValuesEnum
)(args.list_managed_instances_results.upper())
patch_instance_group_manager.instanceLifecyclePolicy = (
managed_instance_groups_utils.CreateInstanceLifecyclePolicy(
client.messages, args
)
)
patch_instance_group_manager.instanceFlexibilityPolicy = (
managed_instance_groups_utils.CreateInstanceFlexibilityPolicy(
args, client.messages, igm_resource
)
)
if args.IsSpecified('size'):
patch_instance_group_manager.targetSize = args.size
standby_policy = managed_instance_groups_utils.CreateStandbyPolicy(
client.messages,
args.standby_policy_initial_delay,
args.standby_policy_mode,
)
if standby_policy:
patch_instance_group_manager.standbyPolicy = standby_policy
if args.suspended_size:
patch_instance_group_manager.targetSuspendedSize = args.suspended_size
if args.stopped_size:
patch_instance_group_manager.targetStoppedSize = args.stopped_size
resource_policies = managed_instance_groups_utils.CreateResourcePolicies(
client.messages, args
)
patch_instance_group_manager.resourcePolicies = resource_policies
if args.IsKnownAndSpecified('multi_mig'):
if args.multi_mig:
multi_mig_region = self._GetRegionForGroup(igm_ref)
multi_mig_ref = holder.resources.Parse(
args.multi_mig,
params={'region': multi_mig_region, 'project': igm_ref.project},
collection='compute.regionMultiMigs',
)
patch_instance_group_manager.multiMig = multi_mig_ref.SelfLink()
elif args.IsKnownAndSpecified('clear_multi_mig'):
patch_instance_group_manager.multiMig = None
include_fields.append('multiMig')
return patch_instance_group_manager, include_fields
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.ResolveAsResource
)(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client),
)
if igm_ref.Collection() not in [
'compute.instanceGroupManagers',
'compute.regionInstanceGroupManagers',
]:
raise ValueError(
'Unknown reference type {0}'.format(igm_ref.Collection())
)
igm_resource = managed_instance_groups_utils.GetInstanceGroupManagerOrThrow(
igm_ref, client
)
patch_instance_group_manager, include_fields = (
self._CreateInstanceGroupManagerPatch(
args, igm_ref, igm_resource, client, holder
)
)
with client.apitools_client.IncludeFields(include_fields):
return self._MakePatchRequest(
client, igm_ref, patch_instance_group_manager
)
UpdateGA.detailed_help = {
'brief': 'Update a Compute Engine managed instance group.',
'DESCRIPTION': """\
Update a Compute Engine managed instance group.
*{command}* allows you to specify or modify the description and group
policies for an existing managed instance group, including the group's
update policy and optional autohealing and stateful policies
The group's update policy defines how an updated VM configuration is
applied to existing VMs in the group. For more information, see
[Applying new configurations]
(https://cloud.google.com/compute/docs/instance-groups/updating-migs)
to VMs in a MIG.
A stateful policy defines which resources should be preserved across the
group. When instances in the group are recreated, stateful resources are
preserved. This command allows you to update stateful resources,
specifically to add or remove stateful disks.
When updating the autohealing policy, you can specify the health check,
initial delay, or both. If either field is unspecified, its value won't
be modified. If `--health-check` is specified, the health check monitors
the health of your application. Whenever the health check signal for an
instance becomes `UNHEALTHY`, the autohealer recreates the instance.
If no health check exists, instance autohealing is triggered only by
instance status: if an instance is not `RUNNING`, the group recreates it.
""",
}
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class UpdateBeta(UpdateGA):
"""Update a Compute Engine managed instance group."""
support_update_policy_min_ready_flag = True
support_multi_mig_flag = True
@classmethod
def Args(cls, parser):
managed_flags.AddMigActionOnVmFailedHealthCheck(parser)
managed_flags.AddOnRepairFlags(parser)
super(UpdateBeta, cls).Args(parser)
def _CreateInstanceGroupManagerPatch(
self, args, igm_ref, igm_resource, client, holder
):
patch_instance_group_manager, include_fields = super(
UpdateBeta, self
)._CreateInstanceGroupManagerPatch(
args, igm_ref, igm_resource, client, holder
)
return patch_instance_group_manager, include_fields
UpdateBeta.detailed_help = UpdateGA.detailed_help
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class UpdateAlpha(UpdateBeta):
"""Update a Compute Engine managed instance group."""
support_multi_mig_flag = True
@classmethod
def Args(cls, parser):
super(UpdateAlpha, cls).Args(parser)
def _CreateInstanceGroupManagerPatch(
self, args, igm_ref, igm_resource, client, holder
):
igm_patch, include_fields = super(
UpdateAlpha, self
)._CreateInstanceGroupManagerPatch(
args, igm_ref, igm_resource, client, holder
)
return igm_patch, include_fields
UpdateAlpha.detailed_help = UpdateBeta.detailed_help

View File

@@ -0,0 +1,172 @@
# -*- 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 to PATCH-style update autoscaling for a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import managed_instance_groups_utils as mig_utils
from googlecloudsdk.api_lib.compute.instance_groups.managed import autoscalers as autoscalers_api
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.util.apis import arg_utils
from googlecloudsdk.core import exceptions
def _CommonArgs(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
mig_utils.GetModeFlag().AddToParser(parser)
mig_utils.AddScaleInControlFlag(parser, include_clear=True)
mig_utils.AddMinMaxControl(parser, max_required=False)
mig_utils.AddScheduledAutoscaling(parser, patch_args=True)
class NoMatchingAutoscalerFoundError(exceptions.Error):
pass
@base.ReleaseTracks(base.ReleaseTrack.GA)
class UpdateAutoscaling(base.Command):
"""Update autoscaling parameters of a managed instance group."""
clear_scale_down = False
@staticmethod
def Args(parser):
_CommonArgs(parser)
mig_utils.AddPredictiveAutoscaling(parser, standard=False)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = instance_groups_flags.CreateGroupReference(
client, holder.resources, args)
# Assert that Instance Group Manager exists.
mig_utils.GetInstanceGroupManagerOrThrow(igm_ref, client)
old_autoscaler = mig_utils.AutoscalerForMigByRef(client, holder.resources,
igm_ref)
if mig_utils.IsAutoscalerNew(old_autoscaler):
raise NoMatchingAutoscalerFoundError(
'Instance group manager [{}] has no existing autoscaler; '
'cannot update.'.format(igm_ref.Name()))
autoscalers_client = autoscalers_api.GetClient(client, igm_ref)
new_autoscaler = autoscalers_client.message_type(
name=old_autoscaler.name, # PATCH needs this
autoscalingPolicy=client.messages.AutoscalingPolicy())
if args.IsSpecified('mode'):
mode = mig_utils.ParseModeString(args.mode, client.messages)
new_autoscaler.autoscalingPolicy.mode = mode
if args.IsSpecified('clear_scale_in_control'):
new_autoscaler.autoscalingPolicy.scaleInControl = None
else:
new_autoscaler.autoscalingPolicy.scaleInControl = \
mig_utils.BuildScaleIn(args, client.messages)
if self.clear_scale_down and args.IsSpecified('clear_scale_down_control'):
new_autoscaler.autoscalingPolicy.scaleDownControl = None
if args.IsSpecified('cpu_utilization_predictive_method'):
cpu_predictive_enum = client.messages.AutoscalingPolicyCpuUtilization.PredictiveMethodValueValuesEnum
new_autoscaler.autoscalingPolicy.cpuUtilization = client.messages.AutoscalingPolicyCpuUtilization(
)
new_autoscaler.autoscalingPolicy.cpuUtilization.predictiveMethod = arg_utils.ChoiceToEnum(
args.cpu_utilization_predictive_method, cpu_predictive_enum)
scheduled = mig_utils.BuildSchedules(args, client.messages)
if scheduled:
new_autoscaler.autoscalingPolicy.scalingSchedules = scheduled
if args.IsSpecified('min_num_replicas'):
new_autoscaler.autoscalingPolicy.minNumReplicas = args.min_num_replicas
if args.IsSpecified('max_num_replicas'):
new_autoscaler.autoscalingPolicy.maxNumReplicas = args.max_num_replicas
return self._SendPatchRequest(args, client, autoscalers_client, igm_ref,
new_autoscaler)
def _SendPatchRequest(self, args, client, autoscalers_client, igm_ref,
new_autoscaler):
if args.IsSpecified('clear_scale_in_control'):
# Apitools won't send null fields unless explicitly told to.
with client.apitools_client.IncludeFields(
['autoscalingPolicy.scaleInControl']):
return autoscalers_client.Patch(igm_ref, new_autoscaler)
elif self.clear_scale_down and args.IsSpecified('clear_scale_down_control'):
with client.apitools_client.IncludeFields(
['autoscalingPolicy.scaleDownControl']):
return autoscalers_client.Patch(igm_ref, new_autoscaler)
else:
return autoscalers_client.Patch(igm_ref, new_autoscaler)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class UpdateAutoscalingBeta(UpdateAutoscaling):
"""Update autoscaling parameters of a managed instance group."""
clear_scale_down = True
@staticmethod
def Args(parser):
_CommonArgs(parser)
mig_utils.AddPredictiveAutoscaling(parser, standard=False)
mig_utils.AddClearScaleDownControlFlag(parser)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class UpdateAutoscalingAlpha(UpdateAutoscalingBeta):
"""Update autoscaling parameters of a managed instance group."""
clear_scale_down = True
@staticmethod
def Args(parser):
_CommonArgs(parser)
mig_utils.AddPredictiveAutoscaling(parser)
mig_utils.AddClearScaleDownControlFlag(parser)
UpdateAutoscaling.detailed_help = {
'brief': 'Update autoscaling parameters of a managed instance group',
'EXAMPLES':
"""\
To update an existing instance group:
$ {command} --mode=only-scale-out
""",
'DESCRIPTION': """
*{command}* updates autoscaling parameters of specified managed instance
group.
Autoscalers can use one or more autoscaling signals. Information on using
multiple autoscaling signals can be found here: [](https://cloud.google.com/compute/docs/autoscaler/multiple-signals)
In contrast to *{parent_command} set-autoscaling*, this command *only* updates
specified fields. For instance:
$ {command} --mode only-scale-out
would change the *mode* field of the autoscaler policy, but leave the rest of
the settings intact.
""",
}
UpdateAutoscalingAlpha.detailed_help = UpdateAutoscaling.detailed_help
UpdateAutoscalingBeta.detailed_help = UpdateAutoscaling.detailed_help

View File

@@ -0,0 +1,169 @@
# -*- 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 for updating instances in a managed instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.managed import flags as instance_groups_managed_flags
from googlecloudsdk.command_lib.compute.managed_instance_groups import update_instances_utils
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class UpdateInstances(base.Command):
r"""Immediately update selected instances in a Compute Engine managed instance group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(project(),
zone(),
instanceName:label=INSTANCE,
status)""")
instance_groups_managed_flags.AddUpdateInstancesArgs(parser=parser)
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
igm_ref = (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
.ResolveAsResource)(
args,
holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client))
update_instances_utils.ValidateIgmReference(igm_ref)
if igm_ref.Collection() == 'compute.instanceGroupManagers':
minimal_action = update_instances_utils.ParseInstanceActionFlag(
'--minimal-action', args.minimal_action or 'none',
client.messages.InstanceGroupManagersApplyUpdatesRequest
.MinimalActionValueValuesEnum)
most_disruptive_allowed_action = (
update_instances_utils.ParseInstanceActionFlag)(
'--most-disruptive-allowed-action',
args.most_disruptive_allowed_action or 'replace',
client.messages.InstanceGroupManagersApplyUpdatesRequest
.MostDisruptiveAllowedActionValueValuesEnum)
instances_holder_field = 'instanceGroupManagersApplyUpdatesRequest'
request = self._CreateZonalApplyUpdatesRequest(
igm_ref, minimal_action, most_disruptive_allowed_action, client)
elif igm_ref.Collection() == 'compute.regionInstanceGroupManagers':
minimal_action = update_instances_utils.ParseInstanceActionFlag(
'--minimal-action', args.minimal_action or 'none',
client.messages.RegionInstanceGroupManagersApplyUpdatesRequest
.MinimalActionValueValuesEnum)
most_disruptive_allowed_action = (
update_instances_utils.ParseInstanceActionFlag)(
'--most-disruptive-allowed-action',
args.most_disruptive_allowed_action or 'replace',
client.messages.RegionInstanceGroupManagersApplyUpdatesRequest
.MostDisruptiveAllowedActionValueValuesEnum)
instances_holder_field = 'regionInstanceGroupManagersApplyUpdatesRequest'
request = self._CreateRegionalApplyUpdatesRequest(
igm_ref, minimal_action, most_disruptive_allowed_action, client)
else:
raise ValueError('Unknown reference type {0}'.format(
igm_ref.Collection()))
if args.all_instances:
return instance_groups_utils.SendAllInstancesRequest(
api_holder=holder,
method_name='ApplyUpdatesToInstances',
request_template=request,
all_instances_holder_field=instances_holder_field,
igm_ref=igm_ref)
else:
return instance_groups_utils.SendInstancesRequestsAndPostProcessOutputs(
api_holder=holder,
method_name='ApplyUpdatesToInstances',
request_template=request,
instances_holder_field=instances_holder_field,
igm_ref=igm_ref,
instances=args.instances)
def _CreateZonalApplyUpdatesRequest(self, igm_ref, minimal_action,
most_disruptive_allowed_action, client):
return client.messages.ComputeInstanceGroupManagersApplyUpdatesToInstancesRequest(
instanceGroupManager=igm_ref.Name(),
instanceGroupManagersApplyUpdatesRequest=client.messages
.InstanceGroupManagersApplyUpdatesRequest(
instances=[],
minimalAction=minimal_action,
mostDisruptiveAllowedAction=most_disruptive_allowed_action),
project=igm_ref.project,
zone=igm_ref.zone)
def _CreateRegionalApplyUpdatesRequest(self, igm_ref, minimal_action,
most_disruptive_allowed_action,
client):
return client.messages.ComputeRegionInstanceGroupManagersApplyUpdatesToInstancesRequest(
instanceGroupManager=igm_ref.Name(),
regionInstanceGroupManagersApplyUpdatesRequest=client.messages
.RegionInstanceGroupManagersApplyUpdatesRequest(
instances=[],
minimalAction=minimal_action,
mostDisruptiveAllowedAction=most_disruptive_allowed_action),
project=igm_ref.project,
region=igm_ref.region,
)
UpdateInstances.detailed_help = {
'brief':
'Immediately update selected instances in a Compute Engine '
'managed instance group.',
'DESCRIPTION':
"""\
When using a managed instance group, it's possible that your intended
specification for a VM is different from the current state of that VM. For
example, this can happen due to changes to the group's target instance
template. This command enables you to initiate the update process on the given
set of instances instantly, thus when your Managed Instance Group is stable
you can be sure that all the changes were applied.
*{command}* allows you to specify the least and the most disruptive actions
that can be performed while updating the instances. This way you can reduce
the risk of rolling out too many changes at once. Possible actions are:
`none`, `refresh`, `restart` and `replace`. The level of disruption to the
instance is ordered as: `none` < `refresh` < `restart` < `replace`.
The command returns the operation status per instance, which might be
``FAIL'', ``SUCCESS'', or ``MEMBER_NOT_FOUND''. ``MEMBER_NOT_FOUND''
is returned only for regional groups when the gcloud command-line tool
wasn't able to resolve the zone from the instance name.
""",
'EXAMPLES':
"""\
To update instances `instance-1`, `instance-2` in `my-group`,
with `minimal-action=none` and `most-disruptive-allowed-action=restart`,
run:
$ {command} \\
my-group --instances=instance-1,instance2 \\
--minimal-action=none
--most-disruptive-allowed-action=restart
"""
}

View File

@@ -0,0 +1,110 @@
# -*- 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 for waiting until managed instance group reaches desired state."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute.instance_groups.managed import wait_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
def _AddArgs(parser, beta=False):
"""Adds args."""
parser.add_argument(
'--timeout',
type=int,
help='Waiting time in seconds for the group '
'to reach the desired state.')
event_type = parser.add_mutually_exclusive_group(required=True)
event_type.add_argument('--version-target-reached',
action='store_true',
default=False,
help='Wait until version target is reached.')
if beta:
event_type.add_argument(
'--all-instances-config-effective',
action='store_true',
default=False,
help="Wait until the group's all-instances configuration is applied "
"to all VMs in the group.")
event_type.add_argument('--stable',
action='store_true',
default=False,
help='Wait until the group is stable.')
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class WaitUntilGA(base.Command):
"""Wait until the managed instance group reaches the desired state."""
@staticmethod
def Args(parser):
_AddArgs(parser=parser)
def CreateGroupReference(self, client, resources, args):
return (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG
.ResolveAsResource)(
args,
resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client))
def Run(self, args):
"""Issues requests necessary to wait until stable on a MIG."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = self.CreateGroupReference(client, holder.resources, args)
if args.stable:
igm_state = wait_utils.IgmState.STABLE
elif args.version_target_reached:
igm_state = wait_utils.IgmState.VERSION_TARGET_REACHED
elif args.all_instances_config_effective:
igm_state = wait_utils.IgmState.ALL_INSTANCES_CONFIG_EFFECTIVE
wait_utils.WaitForIgmState(client, group_ref, igm_state, args.timeout)
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class WaitUntilBeta(WaitUntilGA):
"""Wait until the managed instance group reaches the desired state."""
@staticmethod
def Args(parser):
_AddArgs(parser=parser, beta=True)
WaitUntilGA.detailed_help = {
'brief':
'Wait until the managed instance group reaches the desired state.',
'EXAMPLES':
"""\
To wait until the managed instance group ``instance-group-1'' is stable,
run:
$ {command} --stable instance-group-1
""",
}
WaitUntilBeta.detailed_help = WaitUntilGA.detailed_help

View File

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for waiting until managed instance group becomes stable."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute.instance_groups.managed import wait_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
def _AddArgs(parser):
"""Adds args."""
parser.add_argument('--timeout',
type=int,
help='Timeout in seconds for waiting '
'for group becoming stable.')
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.AddArgument(
parser)
_DEPRECATION_WARNING = (
'`gcloud compute instance-groups managed wait-until-stable` is deprecated. '
'Please use `gcloud compute instance-groups managed wait-until --stable` '
'instead.')
@base.Deprecate(is_removed=False, warning=_DEPRECATION_WARNING)
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class WaitUntilStable(base.Command):
"""Waits until state of managed instance group is stable."""
_TIME_BETWEEN_POLLS_SEC = 10
@staticmethod
def Args(parser):
_AddArgs(parser=parser)
def CreateGroupReference(self, client, resources, args):
return (instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_MANAGER_ARG.
ResolveAsResource)(
args,
resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client))
def Run(self, args):
"""Issues requests necessary to wait until stable on a MIG."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = self.CreateGroupReference(client, holder.resources, args)
wait_utils.WaitForIgmState(
client, group_ref, wait_utils.IgmState.STABLE, args.timeout)

View File

@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for setting named ports in instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags
class SetNamedPortsAlpha(base.SilentCommand):
"""Sets named ports for instance groups."""
@staticmethod
def Args(parser):
flags.MULTISCOPE_INSTANCE_GROUP_ARG.AddArgument(parser)
flags.AddNamedPortsArgs(parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = flags.MULTISCOPE_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources, default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=compute_flags.GetDefaultScopeLister(client))
ports = instance_groups_utils.ValidateAndParseNamedPortsArgs(
client.messages, args.named_ports)
# service could be zonal or regional
request, service = instance_groups_utils.GetSetNamedPortsRequestForGroup(
client, group_ref, ports)
return client.MakeRequests([(service, 'SetNamedPorts', request)])
detailed_help = instance_groups_utils.SET_NAMED_PORTS_HELP

View File

@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 reading and manipulating unmanaged instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
class UnmanagedInstanceGroups(base.Group):
"""Read and manipulate Compute Engine unmanaged instance groups."""
UnmanagedInstanceGroups.detailed_help = {
'brief': (
'Read and manipulate Compute Engine unmanaged instance group'),
}

View File

@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for adding instances to unmanaged instance group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
class AddInstances(base.SilentCommand):
r"""Adds instances to an unmanaged instance group by name.
*{command}* adds existing instances to an unmanaged instance group
by name.
For example:
$ {command} my-group \
--instances my-instance-1,my-instance-2 --zone us-central1-a
"""
ZONAL_INSTANCE_GROUP_ARG = None
@staticmethod
def Args(parser):
AddInstances.ZONAL_INSTANCE_GROUP_ARG = (
instance_groups_flags.MakeZonalInstanceGroupArg())
AddInstances.ZONAL_INSTANCE_GROUP_ARG.AddArgument(parser)
parser.add_argument(
'--instances',
required=True,
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
help='A list of names of instances to add to the instance group. '
'These must exist beforehand and must live in the same zone as '
'the instance group.')
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = (
AddInstances.ZONAL_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=None,
scope_lister=flags.GetDefaultScopeLister(client)))
instance_references = []
for instance in args.instances:
ref = holder.resources.Parse(
instance,
params={
'project': group_ref.project,
'zone': group_ref.zone
},
collection='compute.instances')
instance_references.append(ref)
instance_groups_utils.ValidateInstanceInZone(instance_references,
group_ref.zone)
instance_references = [
client.messages.InstanceReference(instance=inst.SelfLink())
for inst in instance_references]
request_payload = client.messages.InstanceGroupsAddInstancesRequest(
instances=instance_references)
request = client.messages.ComputeInstanceGroupsAddInstancesRequest(
instanceGroup=group_ref.Name(),
instanceGroupsAddInstancesRequest=request_payload,
zone=group_ref.zone,
project=group_ref.project
)
return client.MakeRequests(
[(client.apitools_client.instanceGroups, 'AddInstances', request)]
)

View File

@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for creating unmanaged instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import zone_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.command_lib.compute.instance_groups.unmanaged import flags as instance_groups_unmanaged_flags
class Create(base.CreateCommand):
"""Create a Compute Engine unmanaged instance group.
*{command}* creates a new Compute Engine unmanaged
instance group.
For example:
$ {command} example-instance-group --zone us-central1-a
The above example creates one unmanaged instance group called
'example-instance-group' in the ``us-central1-a'' zone.
"""
@staticmethod
def Args(parser):
parser.display_info.AddFormat(instance_groups_unmanaged_flags.LIST_FORMAT)
Create.ZONAL_INSTANCE_GROUP_ARG = (
instance_groups_flags.MakeZonalInstanceGroupArg())
Create.ZONAL_INSTANCE_GROUP_ARG.AddArgument(parser, operation_type='create')
parser.add_argument(
'--description',
help=('Specifies a textual description for the '
'unmanaged instance group.'))
def Run(self, args):
"""Creates and returns an InstanceGroups.Insert request.
Args:
args: the argparse arguments that this command was invoked with.
Returns:
request: a ComputeInstanceGroupsInsertRequest message object
"""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = (
Create.ZONAL_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client)))
zone_resource_fetcher = zone_utils.ZoneResourceFetcher(client)
zone_resource_fetcher.WarnForZonalCreation([group_ref])
request = client.messages.ComputeInstanceGroupsInsertRequest(
instanceGroup=client.messages.InstanceGroup(
name=group_ref.Name(),
description=args.description),
zone=group_ref.zone,
project=group_ref.project)
return client.MakeRequests([(client.apitools_client.instanceGroups,
'Insert', request)])

View File

@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for deleting unmanaged instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags
class Delete(base.DeleteCommand):
r"""Delete Compute Engine unmanaged instance groups.
*{command}* deletes one or more Compute Engine unmanaged
instance groups. This command just deletes the instance group and does
not delete the individual virtual machine instances
in the instance group.
For example:
$ {command} example-instance-group-1 example-instance-group-2 \
--zone us-central1-a
The above example deletes two instance groups, example-instance-group-1
and example-instance-group-2, in the ``us-central1-a'' zone.
"""
@staticmethod
def Args(parser):
Delete.ZonalInstanceGroupArg = flags.MakeZonalInstanceGroupArg(plural=True)
Delete.ZonalInstanceGroupArg.AddArgument(parser, operation_type='delete')
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
instance_group_refs = Delete.ZonalInstanceGroupArg.ResolveAsResource(
args,
holder.resources,
scope_lister=compute_flags.GetDefaultScopeLister(client))
utils.PromptForDeletion(instance_group_refs, 'zone')
requests = []
for instance_group_ref in instance_group_refs:
requests.append((client.apitools_client.instanceGroups, 'Delete',
client.messages.ComputeInstanceGroupsDeleteRequest(
**instance_group_ref.AsDict())))
return client.MakeRequests(requests)

View File

@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""instance-groups unmanaged describe command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import encoding
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute.instance_groups import flags
class Describe(base.DescribeCommand):
"""Describe an instance group."""
@staticmethod
def Args(parser):
Describe.ZonalInstanceGroupArg = flags.MakeZonalInstanceGroupArg()
Describe.ZonalInstanceGroupArg.AddArgument(
parser, operation_type='describe')
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
instance_group_ref = Describe.ZonalInstanceGroupArg.ResolveAsResource(
args,
holder.resources,
scope_lister=compute_flags.GetDefaultScopeLister(client))
request = client.messages.ComputeInstanceGroupsGetRequest(
**instance_group_ref.AsDict())
response = client.MakeRequests([(client.apitools_client.instanceGroups,
'Get', request)])[0]
return instance_groups_utils.ComputeInstanceGroupManagerMembership(
compute_holder=holder,
items=[encoding.MessageToDict(response)],
filter_mode=instance_groups_utils.InstanceGroupFilteringMode.ALL_GROUPS
)[0]
detailed_help = {
'brief': 'Describe an instance group',
'DESCRIPTION': """\
*{command}* displays detailed information about a Google Compute
Engine instance group.
""",
}

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 for listing named ports in instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
from googlecloudsdk.core import properties
@base.ReleaseTracks(base.ReleaseTrack.GA)
class GetNamedPorts(base.ListCommand):
"""Implements get-named-ports command, GA version."""
@staticmethod
def Args(parser):
GetNamedPorts.ZonalInstanceGroupArg = (
instance_groups_flags.MakeZonalInstanceGroupArg())
GetNamedPorts.ZonalInstanceGroupArg.AddArgument(parser)
parser.display_info.AddFormat('table(name, port)')
def Run(self, args):
"""Retrieves response with named ports."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
project = properties.VALUES.core.project.Get(required=True)
group_ref = (
GetNamedPorts.ZonalInstanceGroupArg.ResolveAsResource(
args, holder.resources,
scope_lister=flags.GetDefaultScopeLister(
holder.client, project)))
return instance_groups_utils.OutputNamedPortsForGroup(
group_ref, holder.client)
detailed_help = (
instance_groups_utils.INSTANCE_GROUP_GET_NAMED_PORT_DETAILED_HELP)
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class GetNamedPortsBeta(base.ListCommand):
"""Implements get-named-ports command, alpha, and beta versions."""
@staticmethod
def Args(parser):
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.AddArgument(parser)
parser.display_info.AddFormat('table(name, port)')
def Run(self, args):
"""Retrieves response with named ports."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
project = properties.VALUES.core.project.Get(required=True)
group_ref = (
instance_groups_flags.MULTISCOPE_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=flags.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(
holder.client, project)))
return instance_groups_utils.OutputNamedPortsForGroup(
group_ref, holder.client)
detailed_help = (
instance_groups_utils.INSTANCE_GROUP_GET_NAMED_PORT_DETAILED_HELP)

View File

@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for listing unmanaged instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.api_lib.compute import lister
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
class List(base.ListCommand):
"""List Compute Engine unmanaged instance groups."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(
name,
zone.basename(),
network.basename(),
network.segment(-4):label=NETWORK_PROJECT,
isManaged:label=MANAGED,
size:label=INSTANCES
)
""")
parser.display_info.AddUriFunc(utils.MakeGetUriFunc())
lister.AddZonalListerArgs(parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
request_data = lister.ParseZonalFlags(args, holder.resources)
list_implementation = lister.ZonalLister(
client, client.apitools_client.instanceGroups)
results = lister.Invoke(request_data, list_implementation)
results = (resource for resource in results if 'zone' in resource)
return instance_groups_utils.ComputeInstanceGroupManagerMembership(
compute_holder=holder,
items=results,
filter_mode=instance_groups_utils.InstanceGroupFilteringMode.
ONLY_UNMANAGED_GROUPS)
List.detailed_help = base_classes.GetZonalListerHelp('unmanaged '
'instance groups')

View File

@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""managed-instance-groups list-instances command.
It's an alias for the instance-groups list-instances command.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.api_lib.compute import request_helper
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
class ListInstances(base.ListCommand):
"""Lists instances attached to specified Instance Group."""
@staticmethod
def Args(parser):
parser.display_info.AddFormat(
'table(instance.basename():label=NAME, status)')
parser.display_info.AddUriFunc(
instance_groups_utils.UriFuncForListInstanceRelatedObjects)
ListInstances.ZonalInstanceGroupArg = (
instance_groups_flags.MakeZonalInstanceGroupArg())
ListInstances.ZonalInstanceGroupArg.AddArgument(parser)
flags.AddRegexArg(parser)
def Run(self, args):
"""Retrieves response with instance in the instance group."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
# Note: only zonal resources parsed here.
group_ref = (
ListInstances.ZonalInstanceGroupArg.ResolveAsResource(
args, holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client)))
if args.regexp:
filter_expr = 'instance eq {0}'.format(args.regexp)
else:
filter_expr = None
request = client.messages.ComputeInstanceGroupsListInstancesRequest(
instanceGroup=group_ref.Name(),
instanceGroupsListInstancesRequest=(
client.messages.InstanceGroupsListInstancesRequest()),
zone=group_ref.zone,
filter=filter_expr,
project=group_ref.project)
errors = []
results = list(
request_helper.MakeRequests(
requests=[(client.apitools_client.instanceGroups, 'ListInstances',
request)],
http=client.apitools_client.http,
batch_url=client.batch_url,
errors=errors))
if errors:
utils.RaiseToolException(errors)
return results
ListInstances.detailed_help = {
'brief':
'List instances present in the instance group',
'DESCRIPTION':
"""\
*{command}* list instances in an instance group.
""",
}

View File

@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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 for removing instances from unmanaged instance groups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags as instance_groups_flags
class RemoveInstances(base.SilentCommand):
"""Removes resources from an unmanaged instance group by instance name.
*{command}* removes instances from an unmanaged instance group using
the instance name.
This does not delete the actual instance resources but removes
it from the instance group.
"""
@staticmethod
def Args(parser):
RemoveInstances.ZONAL_INSTANCE_GROUP_ARG = (
instance_groups_flags.MakeZonalInstanceGroupArg())
RemoveInstances.ZONAL_INSTANCE_GROUP_ARG.AddArgument(parser)
parser.add_argument(
'--instances',
required=True,
type=arg_parsers.ArgList(min_length=1),
metavar='INSTANCE',
help='The names of the instances to remove from the instance group.')
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = (
RemoveInstances.ZONAL_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=flags.GetDefaultScopeLister(client)))
instance_references = []
for instance in args.instances:
ref = holder.resources.Parse(
instance,
params={
'project': group_ref.project,
'zone': group_ref.zone
},
collection='compute.instances')
instance_references.append(ref)
instance_groups_utils.ValidateInstanceInZone(instance_references,
group_ref.zone)
instance_references = [
client.messages.InstanceReference(instance=inst.SelfLink())
for inst in instance_references]
request_payload = client.messages.InstanceGroupsRemoveInstancesRequest(
instances=instance_references)
request = client.messages.ComputeInstanceGroupsRemoveInstancesRequest(
instanceGroup=group_ref.Name(),
instanceGroupsRemoveInstancesRequest=request_payload,
zone=group_ref.zone,
project=group_ref.project
)
return client.MakeRequests([(client.apitools_client.instanceGroups,
'RemoveInstances', request)])

View File

@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""instance-groups unmanaged set-named-ports command.
It's an alias for the instance-groups set-named-ports command.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import instance_groups_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.instance_groups import flags
class SetNamedPorts(base.SilentCommand):
"""Sets named ports for instance groups."""
@staticmethod
def Args(parser):
flags.AddNamedPortsArgs(parser)
SetNamedPorts.ZONAL_INSTANCE_GROUP_ARG = flags.MakeZonalInstanceGroupArg()
SetNamedPorts.ZONAL_INSTANCE_GROUP_ARG.AddArgument(parser)
def Run(self, args):
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
group_ref = (
SetNamedPorts.ZONAL_INSTANCE_GROUP_ARG.ResolveAsResource(
args, holder.resources,
default_scope=compute_scope.ScopeEnum.ZONE,
scope_lister=compute_flags.GetDefaultScopeLister(client)))
ports = instance_groups_utils.ValidateAndParseNamedPortsArgs(
client.messages, args.named_ports)
# service should be always zonal
request, _ = instance_groups_utils.GetSetNamedPortsRequestForGroup(
client, group_ref, ports)
return client.MakeRequests([(client.apitools_client.instanceGroups,
'SetNamedPorts', request)])
detailed_help = instance_groups_utils.SET_NAMED_PORTS_HELP