File: //snap/google-cloud-cli/394/lib/surface/projects/create.py
# -*- 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 to create a new project."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.cloudresourcemanager import projects_util
from googlecloudsdk.api_lib.resource_manager import operations
from googlecloudsdk.api_lib.services import enable_api
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.projects import flags as project_flags
from googlecloudsdk.command_lib.projects import util as command_lib_util
from googlecloudsdk.command_lib.resource_manager import flags
from googlecloudsdk.command_lib.util.args import labels_util
from googlecloudsdk.core import exceptions as core_exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core.console import console_io
ID_DESCRIPTION = ('Project IDs are immutable and can be set only during '
'project creation. They must start with a lowercase letter '
'and can have lowercase ASCII letters, digits or hyphens. '
'Project IDs must be between 6 and 30 characters.')
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class Create(base.CreateCommand):
"""Create a new project.
Creates a new project with the given project ID. By default, projects are not
created under a parent resource. To do so, use either the `--organization` or
`--folder` flag.
## EXAMPLES
The following command creates a project with ID `example-foo-bar-1`, name
`Happy project` and label `type=happy`:
$ {command} example-foo-bar-1 --name="Happy project" --labels=type=happy
By default, projects are not created under a parent resource. The following
command creates a project with ID `example-2` with parent `folders/12345`:
$ {command} example-2 --folder=12345
The following command creates a project with ID `example-3` with parent
`organizations/2048`:
$ {command} example-3 --organization=2048
## SEE ALSO
{see_also}
"""
detailed_help = {'see_also': project_flags.CREATE_DELETE_IN_CONSOLE_SEE_ALSO}
@staticmethod
def Args(parser):
"""Default argument specification."""
labels_util.AddCreateLabelsFlags(parser)
if properties.IsDefaultUniverse():
type_ = arg_parsers.RegexpValidator(
r'[a-z][a-z0-9-]{5,29}', ID_DESCRIPTION
)
else:
type_ = arg_parsers.RegexpValidator(
r'^(?!.*-$)(((?:[a-z][\.a-z0-9-]{2,29})\:?)?(?:[a-z][a-z0-9-]{5,29})$)',
ID_DESCRIPTION,
)
parser.add_argument(
'id',
metavar='PROJECT_ID',
type=type_,
nargs='?',
help='ID for the project you want to create.\n\n{0}'.format(
ID_DESCRIPTION
),
)
parser.add_argument(
'--name',
help=(
'Name for the project you want to create. '
'If not specified, will use project id as name.'
),
)
parser.add_argument(
'--enable-cloud-apis',
action='store_true',
default=True
if properties.VALUES.core.universe_domain.Get() == 'googleapis.com'
else False,
help=arg_parsers.UniverseHelpText(
default='Enable `cloudapis.googleapis.com` during creation.',
universe_help='This is not available.\n',
),
)
parser.add_argument(
'--set-as-default',
action='store_true',
default=False,
help='Set newly created project as [core/project] property.',
)
flags.TagsFlag().AddToParser(parser)
flags.OrganizationIdFlag('to use as a parent').AddToParser(parser)
flags.FolderIdFlag('to use as a parent').AddToParser(parser)
def Run(self, args):
"""Default Run method implementation."""
flags.CheckParentFlags(args, parent_required=False)
project_id = args.id
if not project_id and args.name:
candidate = command_lib_util.IdFromName(args.name)
if candidate and console_io.PromptContinue(
'No project ID provided.',
'Use [{}] as project ID'.format(candidate),
throw_if_unattended=True):
project_id = candidate
if not project_id:
raise exceptions.RequiredArgumentException(
'PROJECT_ID', 'an ID or a name must be provided for the new project')
project_ref = command_lib_util.ParseProject(project_id)
labels = labels_util.ParseCreateArgs(
args, projects_util.GetMessages().Project.LabelsValue)
tags = flags.GetTagsFromFlags(
args, projects_util.GetMessages().Project.TagsValue)
try:
create_op = projects_api.Create(
project_ref,
display_name=args.name,
parent=projects_api.ParentNameToResourceId(
flags.GetParentFromFlags(args)),
labels=labels,
tags=tags)
except apitools_exceptions.HttpConflictError:
msg = ('Project creation failed. The project ID you specified is '
'already in use by another project. Please try an alternative '
'ID.')
core_exceptions.reraise(exceptions.HttpException(msg))
log.CreatedResource(project_ref, is_async=True)
create_op = operations.WaitForOperation(create_op)
# Enable cloudapis.googleapis.com
if args.enable_cloud_apis:
log.debug('Enabling cloudapis.googleapis.com')
enable_api.EnableService(project_ref.Name(), 'cloudapis.googleapis.com')
if args.set_as_default:
project_property = properties.FromString('core/project')
properties.PersistProperty(project_property, project_id)
log.status.Print('Updated property [core/project] to [{0}].'
.format(project_id))
return operations.ExtractOperationResponse(create_op,
apis.GetMessagesModule(
'cloudresourcemanager',
'v1').Project)