• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: utf-8 -*-
2# Copyright 2011 Google Inc. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""Implementation of rb command for deleting cloud storage buckets."""
16
17from __future__ import absolute_import
18
19from gslib.cloud_api import NotEmptyException
20from gslib.command import Command
21from gslib.command_argument import CommandArgument
22from gslib.cs_api_map import ApiSelector
23from gslib.exception import CommandException
24from gslib.storage_url import StorageUrlFromString
25from gslib.util import NO_MAX
26
27
28_SYNOPSIS = """
29  gsutil rb [-f] url...
30"""
31
32_DETAILED_HELP_TEXT = ("""
33<B>SYNOPSIS</B>
34""" + _SYNOPSIS + """
35
36
37<B>DESCRIPTION</B>
38  The rb command deletes a bucket. Buckets must be empty before you can delete
39  them.
40
41  Be certain you want to delete a bucket before you do so, as once it is
42  deleted the name becomes available and another user may create a bucket with
43  that name. (But see also "DOMAIN NAMED BUCKETS" under "gsutil help naming"
44  for help carving out parts of the bucket name space.)
45
46
47<B>OPTIONS</B>
48  -f          Continues silently (without printing error messages) despite
49              errors when removing buckets. If some buckets couldn't be removed,
50              gsutil's exit status will be non-zero even if this flag is set.
51""")
52
53
54class RbCommand(Command):
55  """Implementation of gsutil rb command."""
56
57  # Command specification. See base class for documentation.
58  command_spec = Command.CreateCommandSpec(
59      'rb',
60      command_name_aliases=[
61          'deletebucket', 'removebucket', 'removebuckets', 'rmdir'],
62      usage_synopsis=_SYNOPSIS,
63      min_args=1,
64      max_args=NO_MAX,
65      supported_sub_args='f',
66      file_url_ok=False,
67      provider_url_ok=False,
68      urls_start_arg=0,
69      gs_api_support=[ApiSelector.XML, ApiSelector.JSON],
70      gs_default_api=ApiSelector.JSON,
71      argparse_arguments=[
72          CommandArgument.MakeZeroOrMoreCloudBucketURLsArgument()
73      ]
74  )
75  # Help specification. See help_provider.py for documentation.
76  help_spec = Command.HelpSpec(
77      help_name='rb',
78      help_name_aliases=[
79          'deletebucket', 'removebucket', 'removebuckets', 'rmdir'],
80      help_type='command_help',
81      help_one_line_summary='Remove buckets',
82      help_text=_DETAILED_HELP_TEXT,
83      subcommand_help_text={},
84  )
85
86  def RunCommand(self):
87    """Command entry point for the rb command."""
88    self.continue_on_error = False
89    if self.sub_opts:
90      for o, unused_a in self.sub_opts:
91        if o == '-f':
92          self.continue_on_error = True
93
94    did_some_work = False
95    some_failed = False
96    for url_str in self.args:
97      wildcard_url = StorageUrlFromString(url_str)
98      if wildcard_url.IsObject():
99        raise CommandException('"rb" command requires a provider or '
100                               'bucket URL')
101      # Wrap WildcardIterator call in try/except so we can avoid printing errors
102      # with -f option if a non-existent URL listed, permission denial happens
103      # while listing, etc.
104      try:
105        # Materialize iterator results into a list to catch exceptions.
106        # Since this is listing buckets this list shouldn't be too large to fit
107        # in memory at once.
108        # Also, avoid listing all fields to avoid performing unnecessary bucket
109        # metadata GETs. These would also be problematic when billing is
110        # disabled, as deletes are allowed but GetBucket is not.
111        blrs = list(
112            self.WildcardIterator(url_str).IterBuckets(bucket_fields=['id']))
113      except:  # pylint: disable=bare-except
114        some_failed = True
115        if self.continue_on_error:
116          continue
117        else:
118          raise
119      for blr in blrs:
120        url = blr.storage_url
121        self.logger.info('Removing %s...', url)
122        try:
123          self.gsutil_api.DeleteBucket(url.bucket_name, provider=url.scheme)
124        except NotEmptyException as e:
125          some_failed = True
126          if self.continue_on_error:
127            continue
128          elif 'VersionedBucketNotEmpty' in e.reason:
129            raise CommandException('Bucket is not empty. Note: this is a '
130                                   'versioned bucket, so to delete all '
131                                   'objects\nyou need to use:'
132                                   '\n\tgsutil rm -r %s' % url)
133          else:
134            raise
135        except:  # pylint: disable=bare-except
136          some_failed = True
137          if not self.continue_on_error:
138            raise
139        did_some_work = True
140    if not did_some_work:
141      raise CommandException('No URLs matched')
142    return 1 if some_failed else 0
143
144