OLD | NEW |
| (Empty) |
1 # -*- coding: utf-8 -*- | |
2 # Copyright 2012 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 website configuration command for buckets.""" | |
16 | |
17 from __future__ import absolute_import | |
18 | |
19 import getopt | |
20 import sys | |
21 | |
22 from apitools.base.py import encoding | |
23 | |
24 from gslib.command import Command | |
25 from gslib.command_argument import CommandArgument | |
26 from gslib.cs_api_map import ApiSelector | |
27 from gslib.exception import CommandException | |
28 from gslib.help_provider import CreateHelpText | |
29 from gslib.third_party.storage_apitools import storage_v1_messages as apitools_m
essages | |
30 from gslib.util import NO_MAX | |
31 | |
32 | |
33 _SET_SYNOPSIS = """ | |
34 gsutil web set [-m main_page_suffix] [-e error_page] bucket_url... | |
35 """ | |
36 | |
37 _GET_SYNOPSIS = """ | |
38 gsutil web get bucket_url | |
39 """ | |
40 | |
41 _SYNOPSIS = _SET_SYNOPSIS + _GET_SYNOPSIS.lstrip('\n') | |
42 | |
43 _SET_DESCRIPTION = """ | |
44 <B>SET</B> | |
45 The "gsutil web set" command will allow you to configure or disable | |
46 Website Configuration on your bucket(s). The "set" sub-command has the | |
47 following options (leave both options blank to disable): | |
48 | |
49 <B>SET OPTIONS</B> | |
50 -m <index.html> Specifies the object name to serve when a bucket | |
51 listing is requested via the CNAME alias to | |
52 c.storage.googleapis.com. | |
53 | |
54 -e <404.html> Specifies the error page to serve when a request is made | |
55 for a non-existent object via the CNAME alias to | |
56 c.storage.googleapis.com. | |
57 | |
58 """ | |
59 | |
60 _GET_DESCRIPTION = """ | |
61 <B>GET</B> | |
62 The "gsutil web get" command will gets the web semantics configuration for | |
63 a bucket and displays a JSON representation of the configuration. | |
64 | |
65 In Google Cloud Storage, this would look like: | |
66 | |
67 { | |
68 "notFoundPage": "404.html", | |
69 "mainPageSuffix": "index.html" | |
70 } | |
71 | |
72 """ | |
73 | |
74 _DESCRIPTION = """ | |
75 The Website Configuration feature enables you to configure a Google Cloud | |
76 Storage bucket to behave like a static website. This means requests made via a | |
77 domain-named bucket aliased using a Domain Name System "CNAME" to | |
78 c.storage.googleapis.com will work like any other website, i.e., a GET to the | |
79 bucket will serve the configured "main" page instead of the usual bucket | |
80 listing and a GET for a non-existent object will serve the configured error | |
81 page. | |
82 | |
83 For example, suppose your company's Domain name is example.com. You could set | |
84 up a website bucket as follows: | |
85 | |
86 1. Create a bucket called example.com (see the "DOMAIN NAMED BUCKETS" | |
87 section of "gsutil help naming" for details about creating such buckets). | |
88 | |
89 2. Create index.html and 404.html files and upload them to the bucket. | |
90 | |
91 3. Configure the bucket to have website behavior using the command: | |
92 | |
93 gsutil web set -m index.html -e 404.html gs://example.com | |
94 | |
95 4. Add a DNS CNAME record for example.com pointing to c.storage.googleapis.com | |
96 (ask your DNS administrator for help with this). | |
97 | |
98 Now if you open a browser and navigate to http://example.com, it will display | |
99 the main page instead of the default bucket listing. Note: It can take time | |
100 for DNS updates to propagate because of caching used by the DNS, so it may | |
101 take up to a day for the domain-named bucket website to work after you create | |
102 the CNAME DNS record. | |
103 | |
104 Additional notes: | |
105 | |
106 1. Because the main page is only served when a bucket listing request is made | |
107 via the CNAME alias, you can continue to use "gsutil ls" to list the bucket | |
108 and get the normal bucket listing (rather than the main page). | |
109 | |
110 2. The main_page_suffix applies to each subdirectory of the bucket. For | |
111 example, with the main_page_suffix configured to be index.html, a GET | |
112 request for http://example.com would retrieve | |
113 http://example.com/index.html, and a GET request for | |
114 http://example.com/photos would retrieve | |
115 http://example.com/photos/index.html. | |
116 | |
117 3. There is just one 404.html page: For example, a GET request for | |
118 http://example.com/photos/missing would retrieve | |
119 http://example.com/404.html, not http://example.com/photos/404.html. | |
120 | |
121 4. For additional details see | |
122 https://developers.google.com/storage/docs/website-configuration. | |
123 | |
124 The web command has two sub-commands: | |
125 """ + _SET_DESCRIPTION + _GET_DESCRIPTION | |
126 | |
127 _DETAILED_HELP_TEXT = CreateHelpText(_SYNOPSIS, _DESCRIPTION) | |
128 | |
129 _get_help_text = CreateHelpText(_GET_SYNOPSIS, _GET_DESCRIPTION) | |
130 _set_help_text = CreateHelpText(_SET_SYNOPSIS, _SET_DESCRIPTION) | |
131 | |
132 | |
133 class WebCommand(Command): | |
134 """Implementation of gsutil web command.""" | |
135 | |
136 # Command specification. See base class for documentation. | |
137 command_spec = Command.CreateCommandSpec( | |
138 'web', | |
139 command_name_aliases=['setwebcfg', 'getwebcfg'], | |
140 usage_synopsis=_SYNOPSIS, | |
141 min_args=2, | |
142 max_args=NO_MAX, | |
143 supported_sub_args='m:e:', | |
144 file_url_ok=False, | |
145 provider_url_ok=False, | |
146 urls_start_arg=1, | |
147 gs_api_support=[ApiSelector.XML, ApiSelector.JSON], | |
148 gs_default_api=ApiSelector.JSON, | |
149 argparse_arguments={ | |
150 'set': [ | |
151 CommandArgument.MakeZeroOrMoreCloudBucketURLsArgument() | |
152 ], | |
153 'get': [ | |
154 CommandArgument.MakeNCloudBucketURLsArgument(1) | |
155 ] | |
156 } | |
157 ) | |
158 # Help specification. See help_provider.py for documentation. | |
159 help_spec = Command.HelpSpec( | |
160 help_name='web', | |
161 help_name_aliases=['getwebcfg', 'setwebcfg'], | |
162 help_type='command_help', | |
163 help_one_line_summary=( | |
164 'Set a main page and/or error page for one or more buckets'), | |
165 help_text=_DETAILED_HELP_TEXT, | |
166 subcommand_help_text={'get': _get_help_text, 'set': _set_help_text}, | |
167 ) | |
168 | |
169 def _GetWeb(self): | |
170 """Gets website configuration for a bucket.""" | |
171 bucket_url, bucket_metadata = self.GetSingleBucketUrlFromArg( | |
172 self.args[0], bucket_fields=['website']) | |
173 | |
174 if bucket_url.scheme == 's3': | |
175 sys.stdout.write(self.gsutil_api.XmlPassThroughGetWebsite( | |
176 bucket_url, provider=bucket_url.scheme)) | |
177 else: | |
178 if bucket_metadata.website and (bucket_metadata.website.mainPageSuffix or | |
179 bucket_metadata.website.notFoundPage): | |
180 sys.stdout.write(str(encoding.MessageToJson( | |
181 bucket_metadata.website)) + '\n') | |
182 else: | |
183 sys.stdout.write('%s has no website configuration.\n' % bucket_url) | |
184 | |
185 return 0 | |
186 | |
187 def _SetWeb(self): | |
188 """Sets website configuration for a bucket.""" | |
189 main_page_suffix = None | |
190 error_page = None | |
191 if self.sub_opts: | |
192 for o, a in self.sub_opts: | |
193 if o == '-m': | |
194 main_page_suffix = a | |
195 elif o == '-e': | |
196 error_page = a | |
197 | |
198 url_args = self.args | |
199 | |
200 website = apitools_messages.Bucket.WebsiteValue( | |
201 mainPageSuffix=main_page_suffix, notFoundPage=error_page) | |
202 | |
203 # Iterate over URLs, expanding wildcards and setting the website | |
204 # configuration on each. | |
205 some_matched = False | |
206 for url_str in url_args: | |
207 bucket_iter = self.GetBucketUrlIterFromArg(url_str, bucket_fields=['id']) | |
208 for blr in bucket_iter: | |
209 url = blr.storage_url | |
210 some_matched = True | |
211 self.logger.info('Setting website configuration on %s...', blr) | |
212 bucket_metadata = apitools_messages.Bucket(website=website) | |
213 self.gsutil_api.PatchBucket(url.bucket_name, bucket_metadata, | |
214 provider=url.scheme, fields=['id']) | |
215 if not some_matched: | |
216 raise CommandException('No URLs matched') | |
217 return 0 | |
218 | |
219 def RunCommand(self): | |
220 """Command entry point for the web command.""" | |
221 action_subcommand = self.args.pop(0) | |
222 self.ParseSubOpts(check_args=True) | |
223 if action_subcommand == 'get': | |
224 func = self._GetWeb | |
225 elif action_subcommand == 'set': | |
226 func = self._SetWeb | |
227 else: | |
228 raise CommandException(('Invalid subcommand "%s" for the %s command.\n' | |
229 'See "gsutil help web".') % | |
230 (action_subcommand, self.command_name)) | |
231 return func() | |
OLD | NEW |