| OLD | NEW |
| 1 # -*- coding: utf-8 -*- |
| 1 # Copyright 2011 Google Inc. All Rights Reserved. | 2 # Copyright 2011 Google Inc. All Rights Reserved. |
| 2 # | 3 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. | 5 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
| 6 # | 7 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # | 9 # |
| 9 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, | 11 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and | 13 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. | 14 # limitations under the License. |
| 15 """Implementation of mb command for creating cloud storage buckets.""" |
| 14 | 16 |
| 15 import boto | 17 from __future__ import absolute_import |
| 18 |
| 16 import textwrap | 19 import textwrap |
| 17 | 20 |
| 21 from gslib.cloud_api import BadRequestException |
| 18 from gslib.command import Command | 22 from gslib.command import Command |
| 19 from gslib.command import COMMAND_NAME | 23 from gslib.cs_api_map import ApiSelector |
| 20 from gslib.command import COMMAND_NAME_ALIASES | |
| 21 from gslib.command import FILE_URIS_OK | |
| 22 from gslib.command import MAX_ARGS | |
| 23 from gslib.command import MIN_ARGS | |
| 24 from gslib.command import PROVIDER_URIS_OK | |
| 25 from gslib.command import SUPPORTED_SUB_ARGS | |
| 26 from gslib.command import URIS_START_ARG | |
| 27 from gslib.exception import CommandException | 24 from gslib.exception import CommandException |
| 28 from gslib.help_provider import HELP_NAME | 25 from gslib.storage_url import StorageUrlFromString |
| 29 from gslib.help_provider import HELP_NAME_ALIASES | 26 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_m
essages |
| 30 from gslib.help_provider import HELP_ONE_LINE_SUMMARY | |
| 31 from gslib.help_provider import HELP_TEXT | |
| 32 from gslib.help_provider import HelpType | |
| 33 from gslib.help_provider import HELP_TYPE | |
| 34 from gslib.util import NO_MAX | 27 from gslib.util import NO_MAX |
| 35 | 28 |
| 36 _detailed_help_text = (""" | 29 |
| 30 _DETAILED_HELP_TEXT = (""" |
| 37 <B>SYNOPSIS</B> | 31 <B>SYNOPSIS</B> |
| 38 gsutil mb [-c class] [-l location] [-p proj_id] uri... | 32 gsutil mb [-c class] [-l location] [-p proj_id] uri... |
| 39 | 33 |
| 40 | 34 |
| 41 <B>DESCRIPTION</B> | 35 <B>DESCRIPTION</B> |
| 42 The mb command creates a new bucket. Google Cloud Storage has a single | 36 The mb command creates a new bucket. Google Cloud Storage has a single |
| 43 namespace, so you will not be allowed to create a bucket with a name already | 37 namespace, so you will not be allowed to create a bucket with a name already |
| 44 in use by another user. You can, however, carve out parts of the bucket name | 38 in use by another user. You can, however, carve out parts of the bucket name |
| 45 space corresponding to your company's domain name (see "gsutil help naming"). | 39 space corresponding to your company's domain name (see "gsutil help naming"). |
| 46 | 40 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 68 lower availability is acceptable. Durable Reduced Availability storage would | 62 lower availability is acceptable. Durable Reduced Availability storage would |
| 69 not be appropriate for "hot" objects (i.e., objects being accessed frequently) | 63 not be appropriate for "hot" objects (i.e., objects being accessed frequently) |
| 70 or for interactive workloads; however, it might be appropriate for other types | 64 or for interactive workloads; however, it might be appropriate for other types |
| 71 of applications. See the online documentation for pricing and SLA details. | 65 of applications. See the online documentation for pricing and SLA details. |
| 72 | 66 |
| 73 | 67 |
| 74 <B>BUCKET LOCATIONS</B> | 68 <B>BUCKET LOCATIONS</B> |
| 75 If you don't specify a -l option, the bucket will be created in the default | 69 If you don't specify a -l option, the bucket will be created in the default |
| 76 location (US). Otherwise, you can specify one of the available locations: | 70 location (US). Otherwise, you can specify one of the available locations: |
| 77 | 71 |
| 72 - ASIA (Asia) |
| 73 - ASIA-EAST1 (Eastern Asia-Pacific) |
| 78 - EU (European Union) | 74 - EU (European Union) |
| 79 - US (United States | 75 - US (United States) |
| 80 - US-EAST1 (Eastern United States) [1]_ | 76 - US-EAST1 (Eastern United States) [1]_ |
| 81 - US-EAST2 (Eastern United States) [1]_ | 77 - US-EAST2 (Eastern United States) [1]_ |
| 82 - US-EAST3 (Eastern United States) [1]_ | 78 - US-EAST3 (Eastern United States) [1]_ |
| 83 - US-CENTRAL1 (Central United States) [1]_ | 79 - US-CENTRAL1 (Central United States) [1]_ |
| 84 - US-CENTRAL2 (Central United States) [1]_ | 80 - US-CENTRAL2 (Central United States) [1]_ |
| 85 - US-WEST1 (Western United States) [1]_ | 81 - US-WEST1 (Western United States) [1]_ |
| 86 | 82 |
| 87 .. [1] These locations are for `Regional Buckets <https://developers.google.co
m/storage/docs/regional-buckets>`_. | 83 .. [1] These locations are for `Regional Buckets <https://developers.google.co
m/storage/docs/regional-buckets>`_. |
| 88 Regional Buckets is an experimental feature and data stored in these | 84 Regional Buckets is an experimental feature and data stored in these |
| 89 locations is not subject to the usual SLA. See the documentation for | 85 locations is not subject to the usual SLA. See the documentation for |
| (...skipping 12 matching lines...) Expand all Loading... |
| 102 -l location Can be any of the locations described above. Default is US. | 98 -l location Can be any of the locations described above. Default is US. |
| 103 Locations are case insensitive. | 99 Locations are case insensitive. |
| 104 | 100 |
| 105 -p proj_id Specifies the project ID under which to create the bucket. | 101 -p proj_id Specifies the project ID under which to create the bucket. |
| 106 """) | 102 """) |
| 107 | 103 |
| 108 | 104 |
| 109 class MbCommand(Command): | 105 class MbCommand(Command): |
| 110 """Implementation of gsutil mb command.""" | 106 """Implementation of gsutil mb command.""" |
| 111 | 107 |
| 112 # Command specification (processed by parent class). | 108 # Command specification. See base class for documentation. |
| 113 command_spec = { | 109 command_spec = Command.CreateCommandSpec( |
| 114 # Name of command. | 110 'mb', |
| 115 COMMAND_NAME : 'mb', | 111 command_name_aliases=['makebucket', 'createbucket', 'md', 'mkdir'], |
| 116 # List of command name aliases. | 112 min_args=1, |
| 117 COMMAND_NAME_ALIASES : ['makebucket', 'createbucket', 'md', 'mkdir'], | 113 max_args=NO_MAX, |
| 118 # Min number of args required by this command. | 114 supported_sub_args='c:l:p:', |
| 119 MIN_ARGS : 1, | 115 file_url_ok=False, |
| 120 # Max number of args required by this command, or NO_MAX. | 116 provider_url_ok=False, |
| 121 MAX_ARGS : NO_MAX, | 117 urls_start_arg=0, |
| 122 # Getopt-style string specifying acceptable sub args. | 118 gs_api_support=[ApiSelector.XML, ApiSelector.JSON], |
| 123 SUPPORTED_SUB_ARGS : 'c:l:p:', | 119 gs_default_api=ApiSelector.JSON, |
| 124 # True if file URIs acceptable for this command. | 120 ) |
| 125 FILE_URIS_OK : False, | 121 # Help specification. See help_provider.py for documentation. |
| 126 # True if provider-only URIs acceptable for this command. | 122 help_spec = Command.HelpSpec( |
| 127 PROVIDER_URIS_OK : False, | 123 help_name='mb', |
| 128 # Index in args of first URI arg. | 124 help_name_aliases=[ |
| 129 URIS_START_ARG : 0, | 125 'createbucket', 'makebucket', 'md', 'mkdir', 'location', 'dra', |
| 130 } | 126 'dras', 'reduced_availability', 'durable_reduced_availability', 'rr', |
| 131 help_spec = { | 127 'reduced_redundancy', 'standard', 'storage class'], |
| 132 # Name of command or auxiliary help info for which this help applies. | 128 help_type='command_help', |
| 133 HELP_NAME : 'mb', | 129 help_one_line_summary='Make buckets', |
| 134 # List of help name aliases. | 130 help_text=_DETAILED_HELP_TEXT, |
| 135 HELP_NAME_ALIASES : ['createbucket', 'makebucket', 'md', 'mkdir', | 131 subcommand_help_text={}, |
| 136 'location', 'dra', 'dras', 'reduced_availability', | 132 ) |
| 137 'durable_reduced_availability', | |
| 138 'rr', 'reduced_redundancy', | |
| 139 'standard', 'storage class' ], | |
| 140 # Type of help: | |
| 141 HELP_TYPE : HelpType.COMMAND_HELP, | |
| 142 # One line summary of this help. | |
| 143 HELP_ONE_LINE_SUMMARY : 'Make buckets', | |
| 144 # The full help text. | |
| 145 HELP_TEXT : _detailed_help_text, | |
| 146 } | |
| 147 | 133 |
| 148 # Command entry point. | |
| 149 def RunCommand(self): | 134 def RunCommand(self): |
| 150 location = '' | 135 """Command entry point for the mb command.""" |
| 151 storage_class = '' | 136 location = None |
| 137 storage_class = None |
| 152 if self.sub_opts: | 138 if self.sub_opts: |
| 153 for o, a in self.sub_opts: | 139 for o, a in self.sub_opts: |
| 154 if o == '-l': | 140 if o == '-l': |
| 155 location = a | 141 location = a |
| 156 elif o == '-p': | 142 elif o == '-p': |
| 157 self.proj_id_handler.SetProjectId(a) | 143 self.project_id = a |
| 158 elif o == '-c': | 144 elif o == '-c': |
| 159 storage_class = self._Normalize_Storage_Class(a) | 145 storage_class = self._Normalize_Storage_Class(a) |
| 160 | 146 |
| 161 if not self.headers: | 147 bucket_metadata = apitools_messages.Bucket(location=location, |
| 162 headers = {} | 148 storageClass=storage_class) |
| 163 else: | |
| 164 headers = self.headers.copy() | |
| 165 | 149 |
| 166 for bucket_uri_str in self.args: | 150 for bucket_uri_str in self.args: |
| 167 bucket_uri = self.suri_builder.StorageUri(bucket_uri_str) | 151 bucket_uri = StorageUrlFromString(bucket_uri_str) |
| 168 if not bucket_uri.names_bucket(): | 152 if not bucket_uri.IsBucket(): |
| 169 raise CommandException('The mb command requires a URI that specifies a ' | 153 raise CommandException('The mb command requires a URI that specifies a ' |
| 170 'bucket.\n"%s" is not valid.' % bucket_uri) | 154 'bucket.\n"%s" is not valid.' % bucket_uri) |
| 171 self.proj_id_handler.FillInProjectHeaderIfNeeded('mb', bucket_uri, | 155 |
| 172 headers) | |
| 173 self.logger.info('Creating %s...', bucket_uri) | 156 self.logger.info('Creating %s...', bucket_uri) |
| 174 # Pass storage_class param only if this is a GCS bucket. (In S3 the | 157 # Pass storage_class param only if this is a GCS bucket. (In S3 the |
| 175 # storage class is specified on the key object.) | 158 # storage class is specified on the key object.) |
| 176 if bucket_uri.scheme == 'gs': | 159 try: |
| 177 try: | 160 self.gsutil_api.CreateBucket( |
| 178 bucket_uri.create_bucket(headers=headers, location=location, | 161 bucket_uri.bucket_name, project_id=self.project_id, |
| 179 storage_class=storage_class) | 162 metadata=bucket_metadata, provider=bucket_uri.scheme) |
| 180 except boto.exception.StorageResponseError as e: | 163 except BadRequestException as e: |
| 181 if e.status == 400 and e.code == 'DotfulBucketNameNotUnderTld': | 164 if (e.status == 400 and e.reason == 'DotfulBucketNameNotUnderTld' and |
| 182 bucket_name = bucket_uri.bucket_name | 165 bucket_uri.scheme == 'gs'): |
| 183 final_comp = bucket_name[bucket_name.rfind('.')+1:] | 166 bucket_name = bucket_uri.bucket_name |
| 184 raise CommandException('\n'.join(textwrap.wrap( | 167 final_comp = bucket_name[bucket_name.rfind('.')+1:] |
| 168 raise CommandException('\n'.join(textwrap.wrap( |
| 185 'Buckets with "." in the name must be valid DNS names. The bucket' | 169 'Buckets with "." in the name must be valid DNS names. The bucket' |
| 186 ' you are attempting to create (%s) is not a valid DNS name,' | 170 ' you are attempting to create (%s) is not a valid DNS name,' |
| 187 ' because the final component (%s) is not currently a valid part' | 171 ' because the final component (%s) is not currently a valid part' |
| 188 ' of the top-level DNS tree.' % (bucket_name, final_comp)))) | 172 ' of the top-level DNS tree.' % (bucket_name, final_comp)))) |
| 189 else: | 173 else: |
| 190 raise | 174 raise |
| 191 else: | |
| 192 bucket_uri.create_bucket(headers=headers, location=location) | |
| 193 | 175 |
| 194 return 0 | 176 return 0 |
| 195 | 177 |
| 196 def _Normalize_Storage_Class(self, sc): | 178 def _Normalize_Storage_Class(self, sc): |
| 197 sc = sc.upper() | 179 sc = sc.upper() |
| 198 if sc in ('DRA', 'DURABLE_REDUCED_AVAILABILITY'): | 180 if sc in ('DRA', 'DURABLE_REDUCED_AVAILABILITY'): |
| 199 return 'DURABLE_REDUCED_AVAILABILITY' | 181 return 'DURABLE_REDUCED_AVAILABILITY' |
| 200 if sc in ('S', 'STD', 'STANDARD'): | 182 if sc in ('S', 'STD', 'STANDARD'): |
| 201 return 'STANDARD' | 183 return 'STANDARD' |
| 202 return sc | 184 return sc |
| OLD | NEW |