gcloud 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data.tar.gz.sig +2 -3
  2. data/CHANGELOG +4 -0
  3. data/LICENSE +674 -0
  4. data/Manifest +111 -0
  5. data/README.md +4 -3
  6. data/bin/gcutil +53 -0
  7. data/gcloud.gemspec +4 -3
  8. data/packages/gcutil-1.7.1/CHANGELOG +197 -0
  9. data/packages/gcutil-1.7.1/LICENSE +202 -0
  10. data/packages/gcutil-1.7.1/VERSION +1 -0
  11. data/packages/gcutil-1.7.1/gcutil +53 -0
  12. data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
  13. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
  14. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
  15. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
  16. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
  17. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
  18. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
  19. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
  20. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
  21. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
  22. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
  23. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
  24. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
  25. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
  26. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
  27. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
  28. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
  29. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
  30. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
  31. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
  32. data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
  33. data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
  34. data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
  35. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
  36. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
  37. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
  38. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
  39. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
  40. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
  41. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
  42. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
  43. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
  44. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
  45. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
  46. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
  47. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
  48. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
  49. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
  50. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
  51. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
  52. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
  53. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
  54. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
  55. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
  56. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
  57. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
  58. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
  59. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
  60. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
  61. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
  62. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
  63. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
  64. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
  65. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
  66. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
  67. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
  68. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
  69. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
  70. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
  71. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
  72. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
  73. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
  74. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
  75. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
  76. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
  77. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
  78. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
  79. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
  80. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
  81. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
  82. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
  83. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
  84. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
  85. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
  86. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
  87. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
  88. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
  89. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
  90. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
  91. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
  92. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
  93. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
  94. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
  95. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
  96. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
  97. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
  98. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
  99. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
  100. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
  101. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
  102. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
  103. data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
  104. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
  105. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
  106. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
  107. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
  108. data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
  109. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
  110. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
  111. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
  112. data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
  113. data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
  114. data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
  115. data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
  116. data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
  117. metadata +118 -5
  118. 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()