1# -*- coding: utf-8 -*- 2# Copyright 2017 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 requesterpays configuration command for buckets.""" 16 17from __future__ import absolute_import 18from __future__ import print_function 19from __future__ import division 20from __future__ import unicode_literals 21 22from gslib import metrics 23from gslib.command import Command 24from gslib.command_argument import CommandArgument 25from gslib.cs_api_map import ApiSelector 26from gslib.exception import CommandException 27from gslib.exception import NO_URLS_MATCHED_TARGET 28from gslib.help_provider import CreateHelpText 29from gslib.third_party.storage_apitools import storage_v1_messages as apitools_messages 30from gslib.utils.constants import NO_MAX 31 32_SET_SYNOPSIS = """ 33 gsutil requesterpays set <on|off> bucket_url... 34""" 35 36_GET_SYNOPSIS = """ 37 gsutil requesterpays get bucket_url... 38""" 39 40_SYNOPSIS = _SET_SYNOPSIS + _GET_SYNOPSIS.lstrip('\n') 41 42_SET_DESCRIPTION = """ 43<B>SET</B> 44 The "set" sub-command requires an additional sub-command, either "on" or 45 "off", which, respectively, will enable or disable requester pays for the 46 specified bucket(s). 47 48""" 49 50_GET_DESCRIPTION = """ 51<B>GET</B> 52 The "get" sub-command gets the requester pays configuration for a 53 bucket and displays whether or not it is enabled. 54""" 55 56_DESCRIPTION = """ 57 The Requester Pays Configuration feature enables you to configure a Google 58 Cloud Storage bucket to indicate that the requester will pay all costs 59 related to accessing the bucket and its objects. 60 61 The gsutil requesterpays command has two sub-commands: 62""" + _SET_DESCRIPTION + _GET_DESCRIPTION 63 64_DETAILED_HELP_TEXT = CreateHelpText(_SYNOPSIS, _DESCRIPTION) 65 66_get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION) 67_set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION) 68 69 70class RequesterPaysCommand(Command): 71 """Implementation of gsutil requesterpays command.""" 72 73 # Command specification. See base class for documentation. 74 command_spec = Command.CreateCommandSpec( 75 'requesterpays', 76 usage_synopsis=_SYNOPSIS, 77 min_args=2, 78 max_args=NO_MAX, 79 supported_sub_args='', 80 file_url_ok=False, 81 provider_url_ok=False, 82 urls_start_arg=2, 83 gs_api_support=[ 84 # ApiSelector.XML, # TODO: Uncomment once boto changes are added. 85 ApiSelector.JSON, 86 ], 87 gs_default_api=ApiSelector.JSON, 88 argparse_arguments={ 89 'set': [ 90 CommandArgument('mode', choices=['on', 'off']), 91 CommandArgument.MakeZeroOrMoreCloudBucketURLsArgument(), 92 ], 93 'get': [CommandArgument.MakeZeroOrMoreCloudBucketURLsArgument(),] 94 }, 95 ) 96 # Help specification. See help_provider.py for documentation. 97 help_spec = Command.HelpSpec( 98 help_name='requesterpays', 99 help_name_aliases=[], 100 help_type='command_help', 101 help_one_line_summary=( 102 'Enable or disable requester pays for one or more buckets'), 103 help_text=_DETAILED_HELP_TEXT, 104 subcommand_help_text={ 105 'get': _get_help_text, 106 'set': _set_help_text, 107 }, 108 ) 109 110 def _CalculateUrlsStartArg(self): 111 if not self.args: 112 self.RaiseWrongNumberOfArgumentsException() 113 if self.args[0].lower() == 'set': 114 return 2 115 else: 116 return 1 117 118 def _SetRequesterPays(self): 119 """Gets requesterpays configuration for a bucket.""" 120 requesterpays_arg = self.args[0].lower() 121 if requesterpays_arg not in ('on', 'off'): 122 raise CommandException('Argument to "%s set" must be either <on|off>' % 123 (self.command_name)) 124 url_args = self.args[1:] 125 if not url_args: 126 self.RaiseWrongNumberOfArgumentsException() 127 128 # Iterate over URLs, expanding wildcards and set the requesterpays 129 # configuration on each. 130 some_matched = False 131 for url_str in url_args: 132 bucket_iter = self.GetBucketUrlIterFromArg(url_str, bucket_fields=['id']) 133 for blr in bucket_iter: 134 url = blr.storage_url 135 some_matched = True 136 bucket_metadata = apitools_messages.Bucket( 137 billing=apitools_messages.Bucket.BillingValue()) 138 if requesterpays_arg == 'on': 139 self.logger.info('Enabling requester pays for %s...', url) 140 bucket_metadata.billing.requesterPays = True 141 else: 142 self.logger.info('Disabling requester pays for %s...', url) 143 bucket_metadata.billing.requesterPays = False 144 self.gsutil_api.PatchBucket(url.bucket_name, 145 bucket_metadata, 146 provider=url.scheme, 147 fields=['id']) 148 if not some_matched: 149 raise CommandException(NO_URLS_MATCHED_TARGET % list(url_args)) 150 151 def _GetRequesterPays(self): 152 """Gets requesterpays configuration for one or more buckets.""" 153 url_args = self.args 154 155 # Iterate over URLs, expanding wildcards and getting the requesterpays 156 # configuration on each. 157 some_matched = False 158 for url_str in url_args: 159 bucket_iter = self.GetBucketUrlIterFromArg(url_str, 160 bucket_fields=['billing']) 161 for blr in bucket_iter: 162 some_matched = True 163 if blr.root_object.billing and blr.root_object.billing.requesterPays: 164 print('%s: Enabled' % blr.url_string.rstrip('/')) 165 else: 166 print('%s: Disabled' % blr.url_string.rstrip('/')) 167 if not some_matched: 168 raise CommandException(NO_URLS_MATCHED_TARGET % list(url_args)) 169 170 def RunCommand(self): 171 """Command entry point for the requesterpays command.""" 172 action_subcommand = self.args.pop(0) 173 if action_subcommand == 'get': 174 func = self._GetRequesterPays 175 metrics.LogCommandParams(subcommands=[action_subcommand]) 176 elif action_subcommand == 'set': 177 func = self._SetRequesterPays 178 requesterpays_arg = self.args[0].lower() 179 if requesterpays_arg in ('on', 'off'): 180 metrics.LogCommandParams( 181 subcommands=[action_subcommand, requesterpays_arg]) 182 else: 183 raise CommandException( 184 ('Invalid subcommand "%s" for the %s command.\n' 185 'See "gsutil help %s".') % 186 (action_subcommand, self.command_name, self.command_name)) 187 func() 188 return 0 189