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,91 @@
|
|
|
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 installed kernels."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
from google.apputils import appcommands
|
|
21
|
+
import gflags as flags
|
|
22
|
+
|
|
23
|
+
from gcutil import command_base
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
FLAGS = flags.FLAGS
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class KernelCommand(command_base.GoogleComputeCommand):
|
|
31
|
+
"""Base command for working with the kernels collection."""
|
|
32
|
+
|
|
33
|
+
default_sort_field = 'name'
|
|
34
|
+
summary_fields = (('name', 'name'),
|
|
35
|
+
('description', 'description'))
|
|
36
|
+
|
|
37
|
+
detail_fields = (('name', 'name'),
|
|
38
|
+
('description', 'description'),
|
|
39
|
+
('creation-time', 'creationTimestamp'))
|
|
40
|
+
|
|
41
|
+
resource_collection_name = 'kernels'
|
|
42
|
+
|
|
43
|
+
def __init__(self, name, flag_values):
|
|
44
|
+
super(KernelCommand, self).__init__(name, flag_values)
|
|
45
|
+
|
|
46
|
+
def SetApi(self, api):
|
|
47
|
+
"""Set the Google Compute Engine API for the command.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
api: The Google Compute Engine API used by this command.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
None.
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
self._kernels_api = api.kernels()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class GetKernel(KernelCommand):
|
|
60
|
+
"""Get a kernel."""
|
|
61
|
+
|
|
62
|
+
def __init__(self, name, flag_values):
|
|
63
|
+
super(GetKernel, self).__init__(name, flag_values)
|
|
64
|
+
|
|
65
|
+
def Handle(self, kernel_name):
|
|
66
|
+
"""Get the specified kernel.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
kernel_name: The name of the kernel to get.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
The result of getting the kernel.
|
|
73
|
+
"""
|
|
74
|
+
kernel_request = self._kernels_api.get(
|
|
75
|
+
project=self._project,
|
|
76
|
+
kernel=self.DenormalizeResourceName(kernel_name))
|
|
77
|
+
|
|
78
|
+
return kernel_request.execute()
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ListKernels(KernelCommand, command_base.GoogleComputeListCommand):
|
|
82
|
+
"""List the kernels for a project."""
|
|
83
|
+
|
|
84
|
+
def ListFunc(self):
|
|
85
|
+
"""Returns the fuction for listing kernels."""
|
|
86
|
+
return self._kernels_api.list
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def AddCommands():
|
|
90
|
+
appcommands.AddCmd('getkernel', GetKernel)
|
|
91
|
+
appcommands.AddCmd('listkernels', ListKernels)
|
|
@@ -0,0 +1,56 @@
|
|
|
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 kernel 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 kernel_cmds
|
|
30
|
+
from gcutil import mock_api
|
|
31
|
+
|
|
32
|
+
FLAGS = flags.FLAGS
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class KernelCmdsTest(unittest.TestCase):
|
|
36
|
+
|
|
37
|
+
def testGetKernelGeneratesCorrectRequest(self):
|
|
38
|
+
flag_values = copy.deepcopy(FLAGS)
|
|
39
|
+
|
|
40
|
+
command = kernel_cmds.GetKernel('getkernel', flag_values)
|
|
41
|
+
|
|
42
|
+
expected_project = 'test_project'
|
|
43
|
+
expected_kernel = 'test_kernel'
|
|
44
|
+
flag_values.project = expected_project
|
|
45
|
+
|
|
46
|
+
command.SetFlags(flag_values)
|
|
47
|
+
command.SetApi(mock_api.MockApi())
|
|
48
|
+
|
|
49
|
+
result = command.Handle(expected_kernel)
|
|
50
|
+
|
|
51
|
+
self.assertEqual(result['project'], expected_project)
|
|
52
|
+
self.assertEqual(result['kernel'], expected_kernel)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == '__main__':
|
|
56
|
+
unittest.main()
|
|
@@ -0,0 +1,106 @@
|
|
|
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 machine types."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
from google.apputils import appcommands
|
|
21
|
+
import gflags as flags
|
|
22
|
+
|
|
23
|
+
from gcutil import command_base
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
FLAGS = flags.FLAGS
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MachineTypeCommand(command_base.GoogleComputeCommand):
|
|
31
|
+
"""Base command for working with the machine types collection."""
|
|
32
|
+
|
|
33
|
+
default_sort_field = 'name'
|
|
34
|
+
summary_fields = (('name', 'name'),
|
|
35
|
+
('description', 'description'),
|
|
36
|
+
('cpus', 'guestCpus'),
|
|
37
|
+
('memory-mb', 'memoryMb'),
|
|
38
|
+
('ephemeral-disk-size-gb', 'ephemeralDisks.diskGb'),
|
|
39
|
+
('max-pds', 'maximumPersistentDisks'),
|
|
40
|
+
('max-total-pd-size-gb', 'maximumPersistentDisksSizeGb'))
|
|
41
|
+
|
|
42
|
+
detail_fields = (('name', 'name'),
|
|
43
|
+
('description', 'description'),
|
|
44
|
+
('creation-time', 'creationTimestamp'),
|
|
45
|
+
('cpus', 'guestCpus'),
|
|
46
|
+
('memory-mb', 'memoryMb'),
|
|
47
|
+
('ephemeral-disk-size-gb', 'ephemeralDisks.diskGb'),
|
|
48
|
+
('max-pds', 'maximumPersistentDisks'),
|
|
49
|
+
('max-total-pd-size-gb',
|
|
50
|
+
'maximumPersistentDisksSizeGb'),
|
|
51
|
+
('available-zones', 'availableZone'))
|
|
52
|
+
|
|
53
|
+
resource_collection_name = 'machineTypes'
|
|
54
|
+
|
|
55
|
+
def __init__(self, name, flag_values):
|
|
56
|
+
super(MachineTypeCommand, self).__init__(name, flag_values)
|
|
57
|
+
|
|
58
|
+
def SetApi(self, api):
|
|
59
|
+
"""Set the Google Compute Engine API for the command.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
api: The Google Compute Engine API used by this command.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
None.
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
self._machine_type_api = api.machineTypes()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class GetMachineType(MachineTypeCommand):
|
|
72
|
+
"""Get a machine type."""
|
|
73
|
+
|
|
74
|
+
def __init__(self, name, flag_values):
|
|
75
|
+
super(GetMachineType, self).__init__(name, flag_values)
|
|
76
|
+
|
|
77
|
+
def Handle(self, machine_type_name):
|
|
78
|
+
"""Get the specified machine type.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
machine_type_name: Name of the machine type to get.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
The result of getting the machine type.
|
|
85
|
+
"""
|
|
86
|
+
machine_type_name = self.DenormalizeResourceName(machine_type_name)
|
|
87
|
+
|
|
88
|
+
machine_request = self._machine_type_api.get(
|
|
89
|
+
project=self._project,
|
|
90
|
+
machineType=machine_type_name)
|
|
91
|
+
|
|
92
|
+
return machine_request.execute()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class ListMachineTypes(MachineTypeCommand,
|
|
96
|
+
command_base.GoogleComputeListCommand):
|
|
97
|
+
"""List the machine types for a project."""
|
|
98
|
+
|
|
99
|
+
def ListFunc(self):
|
|
100
|
+
"""Returns the function for listing machine types."""
|
|
101
|
+
return self._machine_type_api.list
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def AddCommands():
|
|
105
|
+
appcommands.AddCmd('getmachinetype', GetMachineType)
|
|
106
|
+
appcommands.AddCmd('listmachinetypes', ListMachineTypes)
|
|
@@ -0,0 +1,59 @@
|
|
|
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 machine type 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 machine_type_cmds
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
from gcutil import mock_api
|
|
34
|
+
except ImportError:
|
|
35
|
+
import mock_api
|
|
36
|
+
|
|
37
|
+
FLAGS = flags.FLAGS
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MachineTypeCmdsTest(unittest.TestCase):
|
|
41
|
+
|
|
42
|
+
def testGetMachineTypeGeneratesCorrectRequest(self):
|
|
43
|
+
flag_values = copy.deepcopy(FLAGS)
|
|
44
|
+
|
|
45
|
+
command = machine_type_cmds.GetMachineType('getmachinetype', flag_values)
|
|
46
|
+
|
|
47
|
+
expected_machine_type = 'test_machine_type'
|
|
48
|
+
flag_values.service_version = command_base.CURRENT_VERSION
|
|
49
|
+
|
|
50
|
+
command.SetFlags(flag_values)
|
|
51
|
+
command.SetApi(mock_api.MockApi())
|
|
52
|
+
|
|
53
|
+
result = command.Handle(expected_machine_type)
|
|
54
|
+
|
|
55
|
+
self.assertEqual(result['machineType'], expected_machine_type)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == '__main__':
|
|
59
|
+
unittest.main()
|
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
"""Helper class for metadata parsing from flags and reading from files."""
|
|
16
|
+
|
|
17
|
+
from __future__ import with_statement
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
from google.apputils import app
|
|
23
|
+
import gflags as flags
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class MetadataFlagsProcessor(object):
|
|
27
|
+
"""Helper class for processing flags and building the metadata list."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, flag_values):
|
|
30
|
+
flags.DEFINE_multistring('metadata',
|
|
31
|
+
[],
|
|
32
|
+
'Metadata to be made available within the VM '
|
|
33
|
+
'environment via the local metadata server. This '
|
|
34
|
+
'should be in the form key:value. Metadata keys '
|
|
35
|
+
'must be unique',
|
|
36
|
+
flag_values=flag_values)
|
|
37
|
+
flags.DEFINE_multistring('metadata_from_file',
|
|
38
|
+
[],
|
|
39
|
+
'Metadata to be made available within the VM '
|
|
40
|
+
'environment via the local metadata server. The '
|
|
41
|
+
'value is loaded from a file. This should be in '
|
|
42
|
+
'the form key:filename. Metadata keys must be '
|
|
43
|
+
'unique',
|
|
44
|
+
flag_values=flag_values)
|
|
45
|
+
self._flags = flag_values
|
|
46
|
+
|
|
47
|
+
def GatherMetadata(self):
|
|
48
|
+
"""Gather the list of metadata dictionaries based on the parsed flag values.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
A list of 'key'/'value' dictionaries defining the metadata.
|
|
52
|
+
Raises:
|
|
53
|
+
app.UsageError: If the parsed flag values are malformed.
|
|
54
|
+
"""
|
|
55
|
+
metadata_dict = {}
|
|
56
|
+
|
|
57
|
+
def CheckKey(key, metadata_dict):
|
|
58
|
+
"""Raises KeyError if key is already in metadata_dict."""
|
|
59
|
+
if key in metadata_dict:
|
|
60
|
+
raise app.UsageError('The key \'%s\' has been specified more than once.'
|
|
61
|
+
' Metadata keys must be unique' % key)
|
|
62
|
+
|
|
63
|
+
def GatherFromList(metadata_entries, metadata_dict):
|
|
64
|
+
for metadata in metadata_entries:
|
|
65
|
+
if ':' not in metadata:
|
|
66
|
+
raise app.UsageError('Wrong syntax for metadata %s. Use key:value.',
|
|
67
|
+
metadata)
|
|
68
|
+
key_value = metadata.split(':', 1)
|
|
69
|
+
key = key_value[0]
|
|
70
|
+
CheckKey(key, metadata_dict)
|
|
71
|
+
value = ''
|
|
72
|
+
if len(key_value) > 1:
|
|
73
|
+
value = key_value[1]
|
|
74
|
+
metadata_dict[key] = value
|
|
75
|
+
|
|
76
|
+
def GatherFromFiles(metadata_files, metadata_dict):
|
|
77
|
+
for metadata_entry in metadata_files:
|
|
78
|
+
if ':' not in metadata_entry:
|
|
79
|
+
raise app.UsageError('Wrong syntax for metadata_from_file %s. '
|
|
80
|
+
'Use key:filename.', metadata_entry)
|
|
81
|
+
key_value = metadata_entry.split(':', 1)
|
|
82
|
+
key = key_value[0]
|
|
83
|
+
CheckKey(key, metadata_dict)
|
|
84
|
+
if len(key_value) != 2:
|
|
85
|
+
raise app.UsageError('No metadata file specified for %s.', key)
|
|
86
|
+
with open(key_value[1], 'r') as f:
|
|
87
|
+
metadata_dict[key] = f.read()
|
|
88
|
+
|
|
89
|
+
GatherFromList(self._flags.metadata, metadata_dict)
|
|
90
|
+
GatherFromFiles(self._flags.metadata_from_file, metadata_dict)
|
|
91
|
+
|
|
92
|
+
result = []
|
|
93
|
+
# We sort here to make testing easier.
|
|
94
|
+
result.extend([{'key': k, 'value': v}
|
|
95
|
+
for (k, v) in sorted(metadata_dict.items())])
|
|
96
|
+
return result
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/usr/bin/python2.4
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2011 Google Inc. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
"""Helper module for fetching metadata variables."""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import datetime
|
|
11
|
+
import json
|
|
12
|
+
import urllib2
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MetadataError(Exception):
|
|
16
|
+
"""Base class for metadata errors."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class NoMetadataServerError(MetadataError):
|
|
21
|
+
"""Metadata server is not responding."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MetadataNotFoundError(MetadataError):
|
|
26
|
+
"""Metadata not present."""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Metadata(object):
|
|
31
|
+
"""Client API for the metadata server."""
|
|
32
|
+
|
|
33
|
+
DEFAULT_METADATA_URL = 'http://metadata.google.internal/0.1/meta-data'
|
|
34
|
+
|
|
35
|
+
def __init__(self, server_address=DEFAULT_METADATA_URL):
|
|
36
|
+
"""Construct a Metadata client.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
server_address: The address of the metadata server.
|
|
40
|
+
"""
|
|
41
|
+
self._server_address = server_address
|
|
42
|
+
|
|
43
|
+
def IsPresent(self):
|
|
44
|
+
"""Return whether the metadata server is ready and available."""
|
|
45
|
+
try:
|
|
46
|
+
self.GetInstanceId(timeout=1)
|
|
47
|
+
return True
|
|
48
|
+
except MetadataError:
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
def GetAttribute(self, path, **kwargs):
|
|
52
|
+
"""Return a string value from the attributes/ subpath.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
path: A subpath under attributes/ on the metadata server.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
The metadata value.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
MetadataError on failure.
|
|
62
|
+
"""
|
|
63
|
+
return self.GetValue('attributes/%s' % (path), **kwargs)
|
|
64
|
+
|
|
65
|
+
def GetValue(self, path, **kwargs):
|
|
66
|
+
"""Return a string value from the metadata server.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
path: The path of the variable.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
The metadata value.
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
MetadataError on failure.
|
|
76
|
+
MetadataNotFoundError if the metadata path is not present.
|
|
77
|
+
NoMetadataServerError if the metadata server does not seem to be present.
|
|
78
|
+
"""
|
|
79
|
+
url = '%s/%s' % (self._server_address, path)
|
|
80
|
+
req = urllib2.Request(url)
|
|
81
|
+
try:
|
|
82
|
+
return self._DoHttpRequestRead(req, **kwargs)
|
|
83
|
+
except urllib2.URLError as e:
|
|
84
|
+
try:
|
|
85
|
+
if e.reason.errno == 111:
|
|
86
|
+
raise NoMetadataServerError('Metadata server not responding')
|
|
87
|
+
if e.reason.errno == -2:
|
|
88
|
+
raise NoMetadataServerError('Metadata server not resolving')
|
|
89
|
+
except AttributeError:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
raise MetadataError('URLError %s: %s' % (url, e))
|
|
93
|
+
except urllib2.HTTPError as e:
|
|
94
|
+
if e.code == 404:
|
|
95
|
+
raise MetadataNotFoundError('Metadata not found: %s' % (path))
|
|
96
|
+
raise MetadataError(
|
|
97
|
+
'Failed to get value %s: %s %s' % (path, e.code, e.reason))
|
|
98
|
+
|
|
99
|
+
def GetJSONValue(self, path, **kwargs):
|
|
100
|
+
"""Return a decoded JSON value from the metadata server.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
path: The path of the variable.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
A json-decoded object.
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
MetadataError on failure.
|
|
110
|
+
MetadataNotFoundError if the metadata path is not present.
|
|
111
|
+
NoMetadataServerError if the metadata server does not seem to be present.
|
|
112
|
+
"""
|
|
113
|
+
try:
|
|
114
|
+
return json.loads(self.GetValue(path, **kwargs))
|
|
115
|
+
except ValueError as e:
|
|
116
|
+
raise MetadataError('Failed to parse JSON: %s', e)
|
|
117
|
+
|
|
118
|
+
def GetAccessScopes(self, restrict_scopes=None,
|
|
119
|
+
service_account='default'):
|
|
120
|
+
"""Return available scopes for service_account.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
restrict_scopes: Only check for these scopes.
|
|
124
|
+
service_account: The service_account to get scopes for.
|
|
125
|
+
|
|
126
|
+
Return:
|
|
127
|
+
A list of scopes.
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
MetadataError on failure.
|
|
131
|
+
"""
|
|
132
|
+
service_account_info = self.GetJSONValue(
|
|
133
|
+
'service-accounts/%s' % service_account)
|
|
134
|
+
scope_set = set(service_account_info['scopes'])
|
|
135
|
+
if restrict_scopes is not None:
|
|
136
|
+
scope_set = scope_set.intersection(set(restrict_scopes))
|
|
137
|
+
return list(scope_set)
|
|
138
|
+
|
|
139
|
+
def GetAccessToken(self, scopes, service_account='default',
|
|
140
|
+
any_available=False):
|
|
141
|
+
"""Get an access token.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
scopes: The set of scopes desired in the access token.
|
|
145
|
+
service_account: The service account to use.
|
|
146
|
+
any_available: Allow only a subset of scopes to be in access token.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
(access-token, expiry-time). Expiry time is a datetime that may be None.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
MetadataError on failure.
|
|
153
|
+
MetadataNotFoundError if the token is not present.
|
|
154
|
+
"""
|
|
155
|
+
if any_available:
|
|
156
|
+
scopes = self.GetAccessScopes(service_account=service_account,
|
|
157
|
+
restrict_scopes=scopes)
|
|
158
|
+
path = 'service-accounts/%s/acquire?scopes=%s' % (
|
|
159
|
+
service_account, '%20'.join(scopes))
|
|
160
|
+
token_info = self.GetJSONValue(path)
|
|
161
|
+
if 'accessToken' not in token_info:
|
|
162
|
+
raise MetadataError('Could not find accessToken in response.')
|
|
163
|
+
|
|
164
|
+
def ExtractExpiry(name):
|
|
165
|
+
"""Try to extract a numeric field name from token_info."""
|
|
166
|
+
if name in token_info:
|
|
167
|
+
try:
|
|
168
|
+
return int(token_info[name])
|
|
169
|
+
except ValueError:
|
|
170
|
+
raise MetadataError(
|
|
171
|
+
'%s field %s is non-numeric' % (name, token_info[name]))
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
# If response provides expiresAt, use it.
|
|
175
|
+
expires_at = ExtractExpiry('expiresAt')
|
|
176
|
+
if expires_at:
|
|
177
|
+
expires_at = datetime.datetime.utcfromtimestamp(expires_at)
|
|
178
|
+
else:
|
|
179
|
+
# Otherwise, look for an expiresIn and use it.
|
|
180
|
+
expires_in = ExtractExpiry('expiresIn')
|
|
181
|
+
if expires_in:
|
|
182
|
+
if expires_in > 1000000000:
|
|
183
|
+
expires_at = datetime.datetime.utcfromtimestamp(expires_in)
|
|
184
|
+
else:
|
|
185
|
+
expires_at = (datetime.datetime.utcnow() +
|
|
186
|
+
datetime.timedelta(seconds=expires_in))
|
|
187
|
+
|
|
188
|
+
return (token_info['accessToken'], expires_at)
|
|
189
|
+
|
|
190
|
+
def AuthHttpRequest(self, http_request, scopes, service_account='default',
|
|
191
|
+
any_available=False):
|
|
192
|
+
"""Add an authorization header to an http request.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
http_request: A urllib2 HTTP Request.
|
|
196
|
+
scopes: The scopes desired on the access token.
|
|
197
|
+
service_account: Which service_account to use.
|
|
198
|
+
any_available: Allow only a subset of scopes to be in access token.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Whether we successfully authorized the request.
|
|
202
|
+
|
|
203
|
+
Raises:
|
|
204
|
+
MetadataError on failure.
|
|
205
|
+
"""
|
|
206
|
+
(token, expiry) = self.GetAccessToken(scopes,
|
|
207
|
+
service_account=service_account,
|
|
208
|
+
any_available=any_available)
|
|
209
|
+
http_request.headers['Authorization'] = ('OAuth %s' % (token))
|
|
210
|
+
return True
|
|
211
|
+
|
|
212
|
+
def GetUserKeys(self, **kwargs):
|
|
213
|
+
"""Get the current user keys from the metadata server.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
A dictionary mapping user names to their ssh keys.
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
MetadataError on failure.
|
|
220
|
+
"""
|
|
221
|
+
keys = self.GetValue('attributes/sshKeys', **kwargs)
|
|
222
|
+
keyof = lambda line: line.split(':', 1)[0]
|
|
223
|
+
return dict(map(lambda line: (keyof(line), line), keys.splitlines()))
|
|
224
|
+
|
|
225
|
+
def GetAttachedDisks(self, **kwargs):
|
|
226
|
+
"""Get the set of disks attached to the VM.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
A list of the disks attached to the VM.
|
|
230
|
+
|
|
231
|
+
Raises:
|
|
232
|
+
MetadataError on failure.
|
|
233
|
+
"""
|
|
234
|
+
data = self.GetJSONValue('attached-disks', **kwargs)
|
|
235
|
+
if 'disks' not in data:
|
|
236
|
+
raise MetadataError('No disks in attached-disks')
|
|
237
|
+
return data['disks']
|
|
238
|
+
|
|
239
|
+
def GetInstanceId(self, **kwargs):
|
|
240
|
+
"""Return the unique instance id of this VM.
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
The unique instance id of this VM.
|
|
244
|
+
|
|
245
|
+
Raises:
|
|
246
|
+
MetadataError on failure.
|
|
247
|
+
"""
|
|
248
|
+
return self.GetValue('instance-id', **kwargs)
|
|
249
|
+
|
|
250
|
+
def GetNumericProjectId(self, **kwargs):
|
|
251
|
+
"""Return the numeric project ID for this VM.
|
|
252
|
+
|
|
253
|
+
This value is typically useful for Google Storage "legacy access."
|
|
254
|
+
Other uses should probably use GetProjectId().
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
The numeric project ID for this VM.
|
|
258
|
+
|
|
259
|
+
Raises:
|
|
260
|
+
MetadataError on failure.
|
|
261
|
+
"""
|
|
262
|
+
return self.GetValue('numeric-project-id', **kwargs)
|
|
263
|
+
|
|
264
|
+
def GetProjectId(self, **kwargs):
|
|
265
|
+
"""Return the unique name of the project for this VM.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
The unique name of the project for this VM.
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
MetadataError on failure.
|
|
272
|
+
"""
|
|
273
|
+
return self.GetValue('project-id', **kwargs)
|
|
274
|
+
|
|
275
|
+
def GetHostname(self, **kwargs):
|
|
276
|
+
"""Get the hostname of the VM.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
The hostname of the VM.
|
|
280
|
+
|
|
281
|
+
Raises:
|
|
282
|
+
MetadataError on failure.
|
|
283
|
+
"""
|
|
284
|
+
return self.GetValue('hostname', **kwargs)
|
|
285
|
+
|
|
286
|
+
def GetTags(self, **kwargs):
|
|
287
|
+
"""Return the list of tags for the VM.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
The list of tags for this VM.
|
|
291
|
+
|
|
292
|
+
Raises:
|
|
293
|
+
MetadataError on failure.
|
|
294
|
+
"""
|
|
295
|
+
return self.GetJSONValue('tags', **kwargs)
|
|
296
|
+
|
|
297
|
+
def GetZone(self, **kwargs):
|
|
298
|
+
"""Return the zone of the VM.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
The zone this VM is running in.
|
|
302
|
+
|
|
303
|
+
Raises:
|
|
304
|
+
MetadataError on failure.
|
|
305
|
+
"""
|
|
306
|
+
return self.GetValue('zone', **kwargs)
|
|
307
|
+
|
|
308
|
+
def GetImage(self, **kwargs):
|
|
309
|
+
"""Return the name of this VM's disk image.
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
The name of this VM's disk image.
|
|
313
|
+
|
|
314
|
+
Raises:
|
|
315
|
+
MetadataError on failure.
|
|
316
|
+
"""
|
|
317
|
+
return self.GetValue('image')
|
|
318
|
+
|
|
319
|
+
def GetMachineType(self, **kwargs):
|
|
320
|
+
"""Return the name of this VM's machine type.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
The name of this VM's machine type.
|
|
324
|
+
|
|
325
|
+
Raises:
|
|
326
|
+
MetadataError on failure.
|
|
327
|
+
"""
|
|
328
|
+
return self.GetValue('machine-type', **kwargs)
|
|
329
|
+
|
|
330
|
+
def GetDescription(self, **kwargs):
|
|
331
|
+
"""Return the description associated with this VM.
|
|
332
|
+
|
|
333
|
+
Returns:
|
|
334
|
+
The description associated with this VM.
|
|
335
|
+
|
|
336
|
+
Raises:
|
|
337
|
+
MetadataError on failure.
|
|
338
|
+
"""
|
|
339
|
+
return self.GetValue('description', **kwargs)
|
|
340
|
+
|
|
341
|
+
def GetNetwork(self, **kwargs):
|
|
342
|
+
"""Return the network configuration for this VM.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
The network configuration for this VM.
|
|
346
|
+
|
|
347
|
+
Raises:
|
|
348
|
+
MetadataError on failure.
|
|
349
|
+
"""
|
|
350
|
+
return self.GetJSONValue('network', **kwargs)
|
|
351
|
+
|
|
352
|
+
def _DoHttpRequestRead(self, request, timeout=None):
|
|
353
|
+
"""Open and return contents of an http request."""
|
|
354
|
+
if timeout is None:
|
|
355
|
+
return urllib2.urlopen(request).read()
|
|
356
|
+
else:
|
|
357
|
+
return urllib2.urlopen(request, timeout=timeout).read()
|