gcloud 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +2 -3
- data/CHANGELOG +4 -0
- data/LICENSE +674 -0
- data/Manifest +111 -0
- data/README.md +4 -3
- data/bin/gcutil +53 -0
- data/gcloud.gemspec +4 -3
- data/packages/gcutil-1.7.1/CHANGELOG +197 -0
- data/packages/gcutil-1.7.1/LICENSE +202 -0
- data/packages/gcutil-1.7.1/VERSION +1 -0
- data/packages/gcutil-1.7.1/gcutil +53 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
- data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
- data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
- data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
- data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
- data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
- data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
- data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
- data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
- metadata +118 -5
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# Copyright 2012 Google Inc. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# 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 obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Commands for interacting with Google Compute Engine firewalls."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
import socket
|
|
20
|
+
|
|
21
|
+
from google.apputils import appcommands
|
|
22
|
+
import gflags as flags
|
|
23
|
+
|
|
24
|
+
from gcutil import command_base
|
|
25
|
+
from gcutil import utils
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
FLAGS = flags.FLAGS
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FirewallCommand(command_base.GoogleComputeCommand):
|
|
32
|
+
"""Base command for working with the firewalls collection."""
|
|
33
|
+
|
|
34
|
+
default_sort_field = 'name'
|
|
35
|
+
summary_fields = (('name', 'name'),
|
|
36
|
+
('description', 'description'),
|
|
37
|
+
('network', 'network'),
|
|
38
|
+
('source-ips', 'sourceRanges'),
|
|
39
|
+
('source-tags', 'sourceTags'),
|
|
40
|
+
('target-tags', 'targetTags'))
|
|
41
|
+
|
|
42
|
+
# The remaining complex fields are filled in via CustomizePrintResult
|
|
43
|
+
detail_fields = (('name', 'name'),
|
|
44
|
+
('description', 'description'),
|
|
45
|
+
('creation-time', 'creationTimestamp'),
|
|
46
|
+
('network', 'network'),
|
|
47
|
+
('source-ips', 'sourceRanges'),
|
|
48
|
+
('source-tags', 'sourceTags'),
|
|
49
|
+
('target-tags', 'targetTags'))
|
|
50
|
+
|
|
51
|
+
resource_collection_name = 'firewalls'
|
|
52
|
+
|
|
53
|
+
def __init__(self, name, flag_values):
|
|
54
|
+
super(FirewallCommand, self).__init__(name, flag_values)
|
|
55
|
+
|
|
56
|
+
def SetApi(self, api):
|
|
57
|
+
"""Set the Google Compute Engine API for the command.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
api: The Google Compute Engine API used by this command.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
None.
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
self._firewalls_api = api.firewalls()
|
|
67
|
+
|
|
68
|
+
def CustomizePrintResult(self, result, table):
|
|
69
|
+
"""Customized result printing for this type.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
result: json dictionary returned by the server
|
|
73
|
+
table: the pretty printing table to be customized
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
None.
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
# Add the rules
|
|
80
|
+
for allowed in result.get('allowed', []):
|
|
81
|
+
as_string = str(allowed['IPProtocol'])
|
|
82
|
+
if allowed.get('ports'):
|
|
83
|
+
as_string += ': %s' % ', '.join(allowed['ports'])
|
|
84
|
+
table.AddRow(('allowed', as_string))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class FirewallRules(object):
|
|
88
|
+
"""Class representing the list of a firewall's rules.
|
|
89
|
+
|
|
90
|
+
This class is only used for parsing a firewall from command-line flags,
|
|
91
|
+
for printing the firewall, we simply dump the JSON.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def ParsePortSpecs(port_spec_strings):
|
|
96
|
+
"""Parse the port-specification portion of firewall rules.
|
|
97
|
+
|
|
98
|
+
This takes the value of the 'allowed' flag and builds the
|
|
99
|
+
corresponding firewall rules, excluding the 'source' fields.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
port_spec_strings: A list of strings specifying the port-specific
|
|
103
|
+
components of a firewall rule. These are of the form
|
|
104
|
+
"(<protocol>)?(:<port>('-'<port>)?)?"
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
A list of dict values containing a protocol string and a list
|
|
108
|
+
of port range strings. This is a substructure of the firewall
|
|
109
|
+
rule dictionaries, which additionally contain a 'source' field.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ValueError: If any of the input strings are malformed.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def _AddToPortSpecs(protocol, port_string, port_specs):
|
|
116
|
+
"""Ensure the specified rule for this protocol allows the given port(s).
|
|
117
|
+
|
|
118
|
+
If there is no port_string specified it implies all ports are allowed,
|
|
119
|
+
and whatever is in the port_specs map for that protocol get clobbered.
|
|
120
|
+
This method also makes sure that any protocol entry without a ports
|
|
121
|
+
member does not get further restricted.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
protocol: The protocol under which the given port range is allowed.
|
|
125
|
+
port_string: The string specification of what ports are allowed.
|
|
126
|
+
port_specs: The mapping from protocols to firewall rules.
|
|
127
|
+
"""
|
|
128
|
+
port_spec_entry = port_specs.setdefault(protocol,
|
|
129
|
+
{'IPProtocol': str(protocol),
|
|
130
|
+
'ports': []})
|
|
131
|
+
if 'ports' in port_spec_entry:
|
|
132
|
+
# We only handle the 'then' case because in the other case the
|
|
133
|
+
# existing entry already allows all ports.
|
|
134
|
+
if not port_string:
|
|
135
|
+
# A missing 'ports' field indicates all ports are allowed.
|
|
136
|
+
port_spec_entry.pop('ports')
|
|
137
|
+
else:
|
|
138
|
+
port_spec_entry['ports'].append(port_string)
|
|
139
|
+
|
|
140
|
+
port_specs = {}
|
|
141
|
+
for port_spec_string in port_spec_strings:
|
|
142
|
+
protocol = None
|
|
143
|
+
port_string = None
|
|
144
|
+
parts = port_spec_string.split(':')
|
|
145
|
+
|
|
146
|
+
if len(parts) > 2:
|
|
147
|
+
raise ValueError('Invalid allowed entry: %s' %
|
|
148
|
+
port_spec_string)
|
|
149
|
+
elif len(parts) == 2:
|
|
150
|
+
if parts[0]:
|
|
151
|
+
protocol = utils.ParseProtocol(parts[0])
|
|
152
|
+
port_string = utils.ReplacePortNames(parts[1])
|
|
153
|
+
else:
|
|
154
|
+
protocol = utils.ParseProtocol(parts[0])
|
|
155
|
+
|
|
156
|
+
if protocol:
|
|
157
|
+
_AddToPortSpecs(protocol, port_string, port_specs)
|
|
158
|
+
else:
|
|
159
|
+
# Add entries for both UPD and TCP
|
|
160
|
+
_AddToPortSpecs(socket.getprotobyname('tcp'), port_string, port_specs)
|
|
161
|
+
_AddToPortSpecs(socket.getprotobyname('udp'), port_string, port_specs)
|
|
162
|
+
|
|
163
|
+
return port_specs.values()
|
|
164
|
+
|
|
165
|
+
def __init__(self, allowed, allowed_ip_sources):
|
|
166
|
+
self.port_specs = FirewallRules.ParsePortSpecs(allowed)
|
|
167
|
+
self.source_ranges = allowed_ip_sources
|
|
168
|
+
self.source_tags = []
|
|
169
|
+
self.target_tags = []
|
|
170
|
+
|
|
171
|
+
def SetTags(self, source_tags, target_tags):
|
|
172
|
+
self.source_tags = sorted(set(source_tags))
|
|
173
|
+
self.target_tags = sorted(set(target_tags))
|
|
174
|
+
|
|
175
|
+
def AddToFirewall(self, firewall):
|
|
176
|
+
if self.source_ranges:
|
|
177
|
+
firewall['sourceRanges'] = self.source_ranges
|
|
178
|
+
if self.source_tags:
|
|
179
|
+
firewall['sourceTags'] = self.source_tags
|
|
180
|
+
if self.target_tags:
|
|
181
|
+
firewall['targetTags'] = self.target_tags
|
|
182
|
+
firewall['allowed'] = self.port_specs
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class AddFirewall(FirewallCommand):
|
|
186
|
+
"""Create a new firewall rule to allow incoming traffic for
|
|
187
|
+
instances on a given network.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
positional_args = '<firewall-name>'
|
|
191
|
+
|
|
192
|
+
def __init__(self, name, flag_values):
|
|
193
|
+
super(AddFirewall, self).__init__(name, flag_values)
|
|
194
|
+
flags.DEFINE_string('description',
|
|
195
|
+
'',
|
|
196
|
+
'Firewall description',
|
|
197
|
+
flag_values=flag_values)
|
|
198
|
+
flags.DEFINE_string('network',
|
|
199
|
+
'default',
|
|
200
|
+
'Which network to apply the firewall to.',
|
|
201
|
+
flag_values=flag_values)
|
|
202
|
+
flags.DEFINE_list('allowed',
|
|
203
|
+
None,
|
|
204
|
+
'The set of allowed ports for this firewall. A list of '
|
|
205
|
+
'specifications of the form '
|
|
206
|
+
'"(<protocol>)?(\':\'<port>(\'-\'<port>)?)?" for allowing'
|
|
207
|
+
' packets through the firewall. Examples: '
|
|
208
|
+
'"tcp:ssh", "udp:5000-6000", "tcp:80", or "icmp".',
|
|
209
|
+
flag_values=flag_values)
|
|
210
|
+
flags.DEFINE_list('allowed_ip_sources',
|
|
211
|
+
[],
|
|
212
|
+
'The set of addresses allowed to talk to the '
|
|
213
|
+
'protocols:ports listed in allowed (comma separated). '
|
|
214
|
+
'If no ip or tag sources are listed, all sources '
|
|
215
|
+
'will be allowed.',
|
|
216
|
+
flag_values=flag_values)
|
|
217
|
+
flags.DEFINE_list('allowed_tag_sources',
|
|
218
|
+
[],
|
|
219
|
+
'The set of tagged instances allowed to talk to the '
|
|
220
|
+
'protocols:ports listed in allowed (comma separated). '
|
|
221
|
+
'If no tag or ip sources are listed, all sources will '
|
|
222
|
+
'be allowed.',
|
|
223
|
+
flag_values=flag_values)
|
|
224
|
+
flags.DEFINE_list('target_tags',
|
|
225
|
+
[],
|
|
226
|
+
'The set of tagged instances to apply the firewall to '
|
|
227
|
+
'(comma separated).',
|
|
228
|
+
flag_values=flag_values)
|
|
229
|
+
|
|
230
|
+
def Handle(self, firewall_name):
|
|
231
|
+
"""Add the specified firewall.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
firewall_name: The name of the firewall to add.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
The result of inserting the firewall.
|
|
238
|
+
|
|
239
|
+
Raises:
|
|
240
|
+
command_base.CommandError: If the passed flag values cannot be
|
|
241
|
+
interpreted.
|
|
242
|
+
"""
|
|
243
|
+
if not self._flags.allowed:
|
|
244
|
+
raise command_base.CommandError(
|
|
245
|
+
'You must specify at least one rule through --allowed.')
|
|
246
|
+
|
|
247
|
+
firewall_resource = {
|
|
248
|
+
'kind': self._GetResourceApiKind('firewall'),
|
|
249
|
+
'name': self.DenormalizeResourceName(firewall_name),
|
|
250
|
+
'description': self._flags.description,
|
|
251
|
+
'rules': []
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if self._flags.network is not None:
|
|
255
|
+
firewall_resource['network'] = (self.NormalizeGlobalResourceName(
|
|
256
|
+
self._project,
|
|
257
|
+
'networks',
|
|
258
|
+
self._flags.network))
|
|
259
|
+
|
|
260
|
+
if (not self._flags.allowed_ip_sources and
|
|
261
|
+
not self._flags.allowed_tag_sources):
|
|
262
|
+
self._flags.allowed_ip_sources.append('0.0.0.0/0')
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
firewall_rules = FirewallRules(self._flags.allowed,
|
|
266
|
+
self._flags.allowed_ip_sources)
|
|
267
|
+
firewall_rules.SetTags(self._flags.allowed_tag_sources,
|
|
268
|
+
self._flags.target_tags)
|
|
269
|
+
firewall_rules.AddToFirewall(firewall_resource)
|
|
270
|
+
firewall_request = self._firewalls_api.insert(project=self._project,
|
|
271
|
+
body=firewall_resource)
|
|
272
|
+
return firewall_request.execute()
|
|
273
|
+
except ValueError, e:
|
|
274
|
+
raise command_base.CommandError(e)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class GetFirewall(FirewallCommand):
|
|
278
|
+
"""Get a firewall."""
|
|
279
|
+
|
|
280
|
+
positional_args = '<firewall-name>'
|
|
281
|
+
|
|
282
|
+
def __init__(self, name, flag_values):
|
|
283
|
+
super(GetFirewall, self).__init__(name, flag_values)
|
|
284
|
+
|
|
285
|
+
def Handle(self, firewall_name):
|
|
286
|
+
"""Get the specified firewall.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
firewall_name: The name of the firewall to get.
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
The result of getting the firewall.
|
|
293
|
+
"""
|
|
294
|
+
firewall_request = self._firewalls_api.get(
|
|
295
|
+
project=self._project,
|
|
296
|
+
firewall=self.DenormalizeResourceName(firewall_name))
|
|
297
|
+
|
|
298
|
+
return firewall_request.execute()
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class DeleteFirewall(FirewallCommand):
|
|
302
|
+
"""Delete one or more firewall rules.
|
|
303
|
+
|
|
304
|
+
If multiple firewall names are specified, the firewalls will be deleted in
|
|
305
|
+
parallel.
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
positional_args = '<firewall-name-1> ... <firewall-name-n>'
|
|
309
|
+
safety_prompt = 'Delete firewall'
|
|
310
|
+
|
|
311
|
+
def __init__(self, name, flag_values):
|
|
312
|
+
super(DeleteFirewall, self).__init__(name, flag_values)
|
|
313
|
+
|
|
314
|
+
def Handle(self, *firewall_names):
|
|
315
|
+
"""Delete the specified firewall.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
*firewall_names: The names of the firewalls to delete.
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Tuple (results, exceptions) - results of deleting the firewalls.
|
|
322
|
+
"""
|
|
323
|
+
requests = []
|
|
324
|
+
for name in firewall_names:
|
|
325
|
+
requests.append(self._firewalls_api.delete(
|
|
326
|
+
project=self._project,
|
|
327
|
+
firewall=self.DenormalizeResourceName(name)))
|
|
328
|
+
results, exceptions = self.ExecuteRequests(requests)
|
|
329
|
+
return (self.MakeListResult(results, 'operationList'), exceptions)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class ListFirewalls(FirewallCommand, command_base.GoogleComputeListCommand):
|
|
333
|
+
"""List the firewall rules for a project."""
|
|
334
|
+
|
|
335
|
+
def ListFunc(self):
|
|
336
|
+
"""Returns the function for listing firewalls."""
|
|
337
|
+
return self._firewalls_api.list
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def AddCommands():
|
|
341
|
+
appcommands.AddCmd('addfirewall', AddFirewall)
|
|
342
|
+
appcommands.AddCmd('getfirewall', GetFirewall)
|
|
343
|
+
appcommands.AddCmd('deletefirewall', DeleteFirewall)
|
|
344
|
+
appcommands.AddCmd('listfirewalls', ListFirewalls)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2012 Google Inc. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
"""Unit tests for the firewall commands."""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
import path_initializer
|
|
22
|
+
path_initializer.InitializeSysPath()
|
|
23
|
+
|
|
24
|
+
import copy
|
|
25
|
+
|
|
26
|
+
import gflags as flags
|
|
27
|
+
import unittest
|
|
28
|
+
|
|
29
|
+
from gcutil import command_base
|
|
30
|
+
from gcutil import firewall_cmds
|
|
31
|
+
from gcutil import mock_api
|
|
32
|
+
|
|
33
|
+
FLAGS = flags.FLAGS
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FirewallRulesTest(unittest.TestCase):
|
|
37
|
+
def testParsePortSpecs(self):
|
|
38
|
+
parse_port_specs = firewall_cmds.FirewallRules.ParsePortSpecs
|
|
39
|
+
self.assertRaises(ValueError, parse_port_specs, [''])
|
|
40
|
+
self.assertRaises(ValueError, parse_port_specs, ['foo'])
|
|
41
|
+
self.assertRaises(ValueError, parse_port_specs, ['foo:'])
|
|
42
|
+
self.assertRaises(ValueError, parse_port_specs, ['tcp:foo-bar'])
|
|
43
|
+
self.assertRaises(ValueError, parse_port_specs, ['tcp:http:https'])
|
|
44
|
+
|
|
45
|
+
self.assertEqual(parse_port_specs([]), [])
|
|
46
|
+
self.assertEqual(parse_port_specs(['tcp']),
|
|
47
|
+
[{'IPProtocol': '6'}])
|
|
48
|
+
self.assertEqual(parse_port_specs(['6']),
|
|
49
|
+
[{'IPProtocol': '6'}])
|
|
50
|
+
self.assertEqual(parse_port_specs(['tcp:80', 'tcp', 'tcp:ssh']),
|
|
51
|
+
[{'IPProtocol': '6'}])
|
|
52
|
+
self.assertEqual(parse_port_specs(['tcp:ssh']),
|
|
53
|
+
[{'IPProtocol': '6',
|
|
54
|
+
'ports': ['22']}])
|
|
55
|
+
self.assertEqual(parse_port_specs([':ssh']),
|
|
56
|
+
[{'IPProtocol': '17',
|
|
57
|
+
'ports': ['22']},
|
|
58
|
+
{'IPProtocol': '6',
|
|
59
|
+
'ports': ['22']}])
|
|
60
|
+
self.assertEqual(parse_port_specs([':ssh']),
|
|
61
|
+
parse_port_specs(['udp:ssh', 'tcp:ssh']))
|
|
62
|
+
self.assertEqual(parse_port_specs([':ssh', 'tcp:80']),
|
|
63
|
+
[{'IPProtocol': '17',
|
|
64
|
+
'ports': ['22']},
|
|
65
|
+
{'IPProtocol': '6',
|
|
66
|
+
'ports': ['22', '80']}])
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class FirewallCmdsTest(unittest.TestCase):
|
|
70
|
+
|
|
71
|
+
def _doAddFirewallGeneratesCorrectRequest(self, service_version,
|
|
72
|
+
allowed_ip_source):
|
|
73
|
+
flag_values = copy.deepcopy(FLAGS)
|
|
74
|
+
|
|
75
|
+
command = firewall_cmds.AddFirewall('addfirewall', flag_values)
|
|
76
|
+
|
|
77
|
+
expected_project = 'test_project'
|
|
78
|
+
expected_firewall = 'test_firewall'
|
|
79
|
+
submitted_network = 'test_network'
|
|
80
|
+
expected_description = 'test firewall'
|
|
81
|
+
flag_values.service_version = service_version
|
|
82
|
+
flag_values.project = expected_project
|
|
83
|
+
flag_values.description = expected_description
|
|
84
|
+
flag_values.network = submitted_network
|
|
85
|
+
flag_values.allowed = [':22']
|
|
86
|
+
if allowed_ip_source:
|
|
87
|
+
flag_values.allowed_ip_sources.append(allowed_ip_source)
|
|
88
|
+
|
|
89
|
+
command.SetFlags(flag_values)
|
|
90
|
+
command.SetApi(mock_api.MockApi())
|
|
91
|
+
|
|
92
|
+
expected_network = command.NormalizeGlobalResourceName(expected_project,
|
|
93
|
+
'networks',
|
|
94
|
+
submitted_network)
|
|
95
|
+
|
|
96
|
+
result = command.Handle(expected_firewall)
|
|
97
|
+
|
|
98
|
+
self.assertEqual(result['project'], expected_project)
|
|
99
|
+
|
|
100
|
+
response_body = result['body']
|
|
101
|
+
self.assertEqual(response_body['name'], expected_firewall)
|
|
102
|
+
self.assertEqual(response_body['network'], expected_network)
|
|
103
|
+
self.assertEqual(response_body['description'], expected_description)
|
|
104
|
+
|
|
105
|
+
self.assertEqual(response_body['sourceRanges'],
|
|
106
|
+
[allowed_ip_source or '0.0.0.0/0'])
|
|
107
|
+
allowed = response_body['allowed']
|
|
108
|
+
self.assertEqual(len(allowed), 2)
|
|
109
|
+
used_protocols = set([x['IPProtocol'] for x in allowed])
|
|
110
|
+
self.assertEqual(used_protocols, set(['6', '17']))
|
|
111
|
+
self.assertEqual(allowed[0]['ports'], allowed[1]['ports'])
|
|
112
|
+
self.assertFalse('sourceTags' in response_body, response_body)
|
|
113
|
+
self.assertFalse('targetTags' in response_body, response_body)
|
|
114
|
+
|
|
115
|
+
def testAddFirewallGeneratesCorrectRequest(self):
|
|
116
|
+
for version in command_base.SUPPORTED_VERSIONS:
|
|
117
|
+
self._doAddFirewallGeneratesCorrectRequest(version, '10.10.10.10/0')
|
|
118
|
+
|
|
119
|
+
def testAddFirewallGeneratesCorrectRequestWithNoAllowedIpSource(self):
|
|
120
|
+
for version in command_base.SUPPORTED_VERSIONS:
|
|
121
|
+
self._doAddFirewallGeneratesCorrectRequest(version,
|
|
122
|
+
allowed_ip_source=None)
|
|
123
|
+
|
|
124
|
+
def testGetFirewallGeneratesCorrectRequest(self):
|
|
125
|
+
flag_values = copy.deepcopy(FLAGS)
|
|
126
|
+
|
|
127
|
+
command = firewall_cmds.GetFirewall('getfirewall', flag_values)
|
|
128
|
+
|
|
129
|
+
expected_project = 'test_project'
|
|
130
|
+
expected_firewall = 'test_firewall'
|
|
131
|
+
flag_values.project = expected_project
|
|
132
|
+
|
|
133
|
+
command.SetFlags(flag_values)
|
|
134
|
+
command.SetApi(mock_api.MockApi())
|
|
135
|
+
|
|
136
|
+
result = command.Handle(expected_firewall)
|
|
137
|
+
|
|
138
|
+
self.assertEqual(result['project'], expected_project)
|
|
139
|
+
self.assertEqual(result['firewall'], expected_firewall)
|
|
140
|
+
|
|
141
|
+
def testDeleteFirewallGeneratesCorrectRequest(self):
|
|
142
|
+
flag_values = copy.deepcopy(FLAGS)
|
|
143
|
+
|
|
144
|
+
command = firewall_cmds.DeleteFirewall('deletefirewall', flag_values)
|
|
145
|
+
|
|
146
|
+
expected_project = 'test_project'
|
|
147
|
+
expected_firewall = 'test_firewall'
|
|
148
|
+
flag_values.project = expected_project
|
|
149
|
+
|
|
150
|
+
command.SetFlags(flag_values)
|
|
151
|
+
command.SetApi(mock_api.MockApi())
|
|
152
|
+
command._credential = mock_api.MockCredential()
|
|
153
|
+
|
|
154
|
+
results, exceptions = command.Handle(expected_firewall)
|
|
155
|
+
self.assertEqual(exceptions, [])
|
|
156
|
+
self.assertEqual(len(results['items']), 1)
|
|
157
|
+
result = results['items'][0]
|
|
158
|
+
|
|
159
|
+
self.assertEqual(result['project'], expected_project)
|
|
160
|
+
self.assertEqual(result['firewall'], expected_firewall)
|
|
161
|
+
|
|
162
|
+
def testDeleteMultipleFirewalls(self):
|
|
163
|
+
flag_values = copy.deepcopy(FLAGS)
|
|
164
|
+
command = firewall_cmds.DeleteFirewall('deletefirewall', flag_values)
|
|
165
|
+
|
|
166
|
+
expected_project = 'test_project'
|
|
167
|
+
expected_firewalls = ['test-firewalls-%02d' % x for x in xrange(100)]
|
|
168
|
+
flag_values.project = expected_project
|
|
169
|
+
|
|
170
|
+
command.SetFlags(flag_values)
|
|
171
|
+
command.SetApi(mock_api.MockApi())
|
|
172
|
+
command._credential = mock_api.MockCredential()
|
|
173
|
+
|
|
174
|
+
results, exceptions = command.Handle(*expected_firewalls)
|
|
175
|
+
self.assertEqual(exceptions, [])
|
|
176
|
+
results = results['items']
|
|
177
|
+
self.assertEqual(len(results), len(expected_firewalls))
|
|
178
|
+
|
|
179
|
+
for expected_firewall, result in zip(expected_firewalls, results):
|
|
180
|
+
self.assertEqual(result['project'], expected_project)
|
|
181
|
+
self.assertEqual(result['firewall'], expected_firewall)
|
|
182
|
+
|
|
183
|
+
def testAddtFirewallsWithTagsGeneratesCorrectRequest(self):
|
|
184
|
+
flag_values = copy.deepcopy(FLAGS)
|
|
185
|
+
|
|
186
|
+
command = firewall_cmds.AddFirewall('addfirewall', flag_values)
|
|
187
|
+
|
|
188
|
+
expected_project = 'test_project'
|
|
189
|
+
expected_firewall = 'test_firewall'
|
|
190
|
+
submitted_network = 'test_network'
|
|
191
|
+
expected_description = 'test firewall'
|
|
192
|
+
expected_source_tags = ['a', 'b']
|
|
193
|
+
expected_target_tags = ['c', 'd']
|
|
194
|
+
flag_values.service_version = 'v1beta13'
|
|
195
|
+
flag_values.project = expected_project
|
|
196
|
+
flag_values.description = expected_description
|
|
197
|
+
flag_values.network = submitted_network
|
|
198
|
+
flag_values.allowed = [':22']
|
|
199
|
+
flag_values.allowed_tag_sources = expected_source_tags
|
|
200
|
+
flag_values.target_tags = expected_target_tags * 2 # Create duplicates
|
|
201
|
+
|
|
202
|
+
command.SetFlags(flag_values)
|
|
203
|
+
command.SetApi(mock_api.MockApi())
|
|
204
|
+
|
|
205
|
+
expected_network = command.NormalizeGlobalResourceName(expected_project,
|
|
206
|
+
'networks',
|
|
207
|
+
submitted_network)
|
|
208
|
+
|
|
209
|
+
result = command.Handle(expected_firewall)
|
|
210
|
+
|
|
211
|
+
self.assertEqual(result['project'], expected_project)
|
|
212
|
+
|
|
213
|
+
response_body = result['body']
|
|
214
|
+
self.assertEqual(response_body['name'], expected_firewall)
|
|
215
|
+
self.assertEqual(response_body['network'], expected_network)
|
|
216
|
+
self.assertEqual(response_body['description'], expected_description)
|
|
217
|
+
|
|
218
|
+
allowed = response_body['allowed']
|
|
219
|
+
self.assertEqual(len(allowed), 2)
|
|
220
|
+
used_protocols = set([allowed[0]['IPProtocol'], allowed[1]['IPProtocol']])
|
|
221
|
+
self.assertEqual(used_protocols, set(['6', '17']))
|
|
222
|
+
self.assertEqual(allowed[0]['ports'], allowed[1]['ports'])
|
|
223
|
+
self.assertEqual(allowed[0]['ports'], ['22'])
|
|
224
|
+
self.assertTrue('sourceTags' in response_body)
|
|
225
|
+
self.assertTrue('targetTags' in response_body)
|
|
226
|
+
self.assertEqual(response_body['sourceTags'], expected_source_tags)
|
|
227
|
+
self.assertEqual(response_body['targetTags'], expected_target_tags)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
if __name__ == '__main__':
|
|
231
|
+
unittest.main()
|