Home | History | Annotate | Download | only in commands
      1 # -*- coding: utf-8 -*-
      2 # Copyright 2013 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 lifecycle configuration command for GCS buckets."""
     16 
     17 from __future__ import absolute_import
     18 
     19 import sys
     20 
     21 from gslib.command import Command
     22 from gslib.command_argument import CommandArgument
     23 from gslib.cs_api_map import ApiSelector
     24 from gslib.exception import CommandException
     25 from gslib.help_provider import CreateHelpText
     26 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_messages
     27 from gslib.translation_helper import LifecycleTranslation
     28 from gslib.util import NO_MAX
     29 from gslib.util import UrlsAreForSingleProvider
     30 
     31 
     32 _GET_SYNOPSIS = """
     33   gsutil lifecycle get url
     34 """
     35 
     36 _SET_SYNOPSIS = """
     37   gsutil lifecycle set config-json-file url...
     38 """
     39 
     40 _SYNOPSIS = _GET_SYNOPSIS + _SET_SYNOPSIS.lstrip('\n') + '\n'
     41 
     42 _GET_DESCRIPTION = """
     43 <B>GET</B>
     44   Gets the lifecycle configuration for a given bucket. You can get the
     45   lifecycle configuration for only one bucket at a time. The output can be
     46   redirected into a file, edited and then updated via the set sub-command.
     47 
     48 """
     49 
     50 _SET_DESCRIPTION = """
     51 <B>SET</B>
     52   Sets the lifecycle configuration on one or more buckets. The config-json-file
     53   specified on the command line should be a path to a local file containing
     54   the lifecycle configuration JSON document.
     55 
     56 """
     57 
     58 _DESCRIPTION = """
     59   The lifecycle command can be used to get or set lifecycle management policies
     60   for the given bucket(s). This command is supported for buckets only, not
     61   objects. For more information on object lifecycle management, please see the
     62   `developer guide <https://developers.google.com/storage/docs/lifecycle>`_.
     63 
     64   The lifecycle command has two sub-commands:
     65 """ + _GET_DESCRIPTION + _SET_DESCRIPTION + """
     66 <B>EXAMPLES</B>
     67   The following lifecycle configuration JSON document specifies that all objects
     68   in this bucket that are more than 365 days old will be deleted automatically:
     69 
     70     {
     71       "rule":
     72       [
     73         {
     74           "action": {"type": "Delete"},
     75           "condition": {"age": 365}
     76         }
     77       ]
     78     }
     79 
     80   The following (empty) lifecycle configuration JSON document removes all
     81   lifecycle configuration for a bucket:
     82 
     83     {}
     84 
     85 """
     86 
     87 _DETAILED_HELP_TEXT = CreateHelpText(_SYNOPSIS, _DESCRIPTION)
     88 
     89 _get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION)
     90 _set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION)
     91 
     92 
     93 class LifecycleCommand(Command):
     94   """Implementation of gsutil lifecycle command."""
     95 
     96   # Command specification. See base class for documentation.
     97   command_spec = Command.CreateCommandSpec(
     98       'lifecycle',
     99       command_name_aliases=['lifecycleconfig'],
    100       usage_synopsis=_SYNOPSIS,
    101       min_args=2,
    102       max_args=NO_MAX,
    103       supported_sub_args='',
    104       file_url_ok=True,
    105       provider_url_ok=False,
    106       urls_start_arg=1,
    107       gs_api_support=[ApiSelector.XML, ApiSelector.JSON],
    108       gs_default_api=ApiSelector.JSON,
    109       argparse_arguments={
    110           'set': [
    111               CommandArgument.MakeNFileURLsArgument(1),
    112               CommandArgument.MakeZeroOrMoreCloudBucketURLsArgument()
    113           ],
    114           'get': [
    115               CommandArgument.MakeNCloudBucketURLsArgument(1)
    116           ]
    117       }
    118   )
    119   # Help specification. See help_provider.py for documentation.
    120   help_spec = Command.HelpSpec(
    121       help_name='lifecycle',
    122       help_name_aliases=['getlifecycle', 'setlifecycle'],
    123       help_type='command_help',
    124       help_one_line_summary=(
    125           'Get or set lifecycle configuration for a bucket'),
    126       help_text=_DETAILED_HELP_TEXT,
    127       subcommand_help_text={'get': _get_help_text, 'set': _set_help_text},
    128   )
    129 
    130   def _SetLifecycleConfig(self):
    131     """Sets lifecycle configuration for a Google Cloud Storage bucket."""
    132     lifecycle_arg = self.args[0]
    133     url_args = self.args[1:]
    134     # Disallow multi-provider 'lifecycle set' requests.
    135     if not UrlsAreForSingleProvider(url_args):
    136       raise CommandException('"%s" command spanning providers not allowed.' %
    137                              self.command_name)
    138 
    139     # Open, read and parse file containing JSON document.
    140     lifecycle_file = open(lifecycle_arg, 'r')
    141     lifecycle_txt = lifecycle_file.read()
    142     lifecycle_file.close()
    143 
    144     # Iterate over URLs, expanding wildcards and setting the lifecycle on each.
    145     some_matched = False
    146     for url_str in url_args:
    147       bucket_iter = self.GetBucketUrlIterFromArg(url_str,
    148                                                  bucket_fields=['lifecycle'])
    149       for blr in bucket_iter:
    150         url = blr.storage_url
    151         some_matched = True
    152         self.logger.info('Setting lifecycle configuration on %s...', blr)
    153         if url.scheme == 's3':
    154           self.gsutil_api.XmlPassThroughSetLifecycle(
    155               lifecycle_txt, url, provider=url.scheme)
    156         else:
    157           lifecycle = LifecycleTranslation.JsonLifecycleToMessage(lifecycle_txt)
    158           bucket_metadata = apitools_messages.Bucket(lifecycle=lifecycle)
    159           self.gsutil_api.PatchBucket(url.bucket_name, bucket_metadata,
    160                                       provider=url.scheme, fields=['id'])
    161     if not some_matched:
    162       raise CommandException('No URLs matched')
    163     return 0
    164 
    165   def _GetLifecycleConfig(self):
    166     """Gets lifecycle configuration for a Google Cloud Storage bucket."""
    167     bucket_url, bucket_metadata = self.GetSingleBucketUrlFromArg(
    168         self.args[0], bucket_fields=['lifecycle'])
    169 
    170     if bucket_url.scheme == 's3':
    171       sys.stdout.write(self.gsutil_api.XmlPassThroughGetLifecycle(
    172           bucket_url, provider=bucket_url.scheme))
    173     else:
    174       if bucket_metadata.lifecycle and bucket_metadata.lifecycle.rule:
    175         sys.stdout.write(LifecycleTranslation.JsonLifecycleFromMessage(
    176             bucket_metadata.lifecycle))
    177       else:
    178         sys.stdout.write('%s has no lifecycle configuration.\n' % bucket_url)
    179 
    180     return 0
    181 
    182   def RunCommand(self):
    183     """Command entry point for the lifecycle command."""
    184     subcommand = self.args.pop(0)
    185     if subcommand == 'get':
    186       return self._GetLifecycleConfig()
    187     elif subcommand == 'set':
    188       return self._SetLifecycleConfig()
    189     else:
    190       raise CommandException('Invalid subcommand "%s" for the %s command.' %
    191                              (subcommand, self.command_name))
    192