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.
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,38 @@
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
+ """Contains a utility for initializing the system path."""
18
+
19
+
20
+
21
+ import os
22
+ import sys
23
+
24
+ def InitializeSysPath():
25
+ """Adds gcutil's dependencies to sys.path.
26
+
27
+ This function assumes that the site module has not been
28
+ imported. The site module can be supressed by launching this program
29
+ using python -S.
30
+ """
31
+ lib_dir = os.path.dirname(os.path.dirname(os.path.dirname(
32
+ os.path.realpath(__file__))))
33
+ libs = [os.path.join(lib_dir, lib) for lib in os.listdir(lib_dir)]
34
+
35
+ # Removes entries from libs that are already on the path.
36
+ libs = list(set(libs) - set(sys.path))
37
+
38
+ sys.path = libs + sys.path
@@ -0,0 +1,173 @@
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."""
16
+
17
+
18
+
19
+ import httplib2
20
+ import json
21
+
22
+
23
+ from google.apputils import appcommands
24
+ import gflags as flags
25
+
26
+ from gcutil import auth_helper
27
+ from gcutil import command_base
28
+ from gcutil import gcutil_logging
29
+ from gcutil import metadata
30
+ from gcutil import scopes
31
+ from gcutil import version
32
+
33
+
34
+ FLAGS = flags.FLAGS
35
+ LOGGER = gcutil_logging.LOGGER
36
+
37
+
38
+ class ProjectCommand(command_base.GoogleComputeCommand):
39
+ """Base command for working with the projects collection."""
40
+
41
+ default_sort_field = 'name'
42
+ summary_fields = (('name', 'name'),
43
+ ('ips', 'externalIpAddresses'))
44
+
45
+ def __init__(self, name, flag_values):
46
+ super(ProjectCommand, self).__init__(name, flag_values)
47
+
48
+ def SetApi(self, api):
49
+ """Set the Google Compute Engine API for the command.
50
+
51
+ Args:
52
+ api: The Google Compute Engine API used by this command.
53
+
54
+ Returns:
55
+ None.
56
+
57
+ """
58
+ self._projects_api = api.projects()
59
+
60
+ def CustomizePrintResult(self, result, table):
61
+ """Customized result printing for this type.
62
+
63
+ Args:
64
+ result: json dictionary returned by the server
65
+ table: the pretty printing table to be customized
66
+
67
+ Returns:
68
+ None.
69
+
70
+ """
71
+ # Add the quotas
72
+ table.AddRow(('', ''))
73
+ table.AddRow(('usage', ''))
74
+ for quota in result.get('quotas', []):
75
+ table.AddRow((' %s' % quota['metric'].lower().replace('_', '-'),
76
+ '%s/%s' % (str(quota['usage']), str(quota['limit']))))
77
+ # Add the metadata
78
+ if result.get('commonInstanceMetadata', []):
79
+ table.AddRow(('', ''))
80
+ table.AddRow(('common-instance-metadata', ''))
81
+ metadata_container = result.get('commonInstanceMetadata', [])
82
+ if 'kind' in metadata_container:
83
+ metadata_container = metadata_container.get('items', [])
84
+ for metadata_entry in metadata_container:
85
+ table.AddRow((' %s' % metadata_entry.get('key', ''),
86
+ self._PresentElement(metadata_entry.get('value', ''))))
87
+
88
+
89
+ class GetProject(ProjectCommand):
90
+ """Get the resource for a Google Compute Engine project."""
91
+
92
+ positional_args = '<project-name>'
93
+
94
+ # The remaining complex fields are filled in via CustomizePrintResult
95
+ detail_fields = (('name', 'name'),
96
+ ('description', 'description'),
97
+ ('creation-time', 'creationTimestamp'),
98
+ ('ips', 'externalIpAddresses'))
99
+
100
+ def __init__(self, name, flag_values):
101
+ super(GetProject, self).__init__(name, flag_values)
102
+
103
+ def Handle(self, project=None):
104
+ """Get the specified project.
105
+
106
+ Args:
107
+ project: The project for which to get defails.
108
+
109
+ Returns:
110
+ The result of getting the project.
111
+ """
112
+ project = project or self._flags.project
113
+ project_request = self._projects_api.get(project=project)
114
+ return project_request.execute()
115
+
116
+
117
+ class SetCommonInstanceMetadata(ProjectCommand):
118
+ """Set the commonInstanceMetadata field for a Google Compute Engine project.
119
+
120
+ This is a blanket overwrite of all of the project wide metadata.
121
+ """
122
+
123
+ def __init__(self, name, flag_values):
124
+ super(SetCommonInstanceMetadata, self).__init__(name, flag_values)
125
+ flags.DEFINE_bool('force',
126
+ False,
127
+ 'Set the metadata even if it erases existing keys',
128
+ flag_values=flag_values,
129
+ short_name='f')
130
+ self._metadata_flags_processor = metadata.MetadataFlagsProcessor(
131
+ flag_values)
132
+
133
+ def Handle(self):
134
+ """Set the metadata common to all instances in the specified project.
135
+
136
+ Args:
137
+ None.
138
+
139
+ Returns:
140
+ The result of setting the project wide metadata.
141
+
142
+ Raises:
143
+
144
+ command_base.CommandError: If the update would cause some metadata to
145
+ be deleted.
146
+ """
147
+ new_metadata = self._metadata_flags_processor.GatherMetadata()
148
+
149
+ if not self._flags.force:
150
+ get_request = self._projects_api.get(project=self._flags.project)
151
+ project_resource = get_request.execute()
152
+ project_metadata = project_resource.get('commonInstanceMetadata', [])
153
+ if 'kind' in project_metadata:
154
+ project_metadata = project_metadata.get('items', [])
155
+ existing_keys = set([entry['key'] for entry in project_metadata])
156
+ new_keys = set([entry['key'] for entry in new_metadata])
157
+ dropped_keys = existing_keys - new_keys
158
+ if dropped_keys:
159
+ raise command_base.CommandError(
160
+ 'Discarding update that would wipe out the following metadata: %s.'
161
+ '\n\nRe-run with the -f flag to force the update.' %
162
+ ', '.join(list(dropped_keys)))
163
+
164
+ project_request = self._projects_api.setCommonInstanceMetadata(
165
+ project=self._flags.project,
166
+ body={'kind': self._GetResourceApiKind('metadata'),
167
+ 'items': new_metadata})
168
+ return project_request.execute()
169
+
170
+
171
+ def AddCommands():
172
+ appcommands.AddCmd('getproject', GetProject)
173
+ appcommands.AddCmd('setcommoninstancemetadata', SetCommonInstanceMetadata)
@@ -0,0 +1,111 @@
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 project commands."""
18
+
19
+
20
+
21
+ import path_initializer
22
+ path_initializer.InitializeSysPath()
23
+
24
+ import copy
25
+ import re
26
+ import tempfile
27
+
28
+
29
+ import gflags as flags
30
+ import unittest
31
+
32
+ from gcutil import auth_helper
33
+ from gcutil import command_base
34
+ from gcutil import flags_cache
35
+ from gcutil import mock_api
36
+ from gcutil import project_cmds
37
+
38
+ FLAGS = flags.FLAGS
39
+
40
+
41
+ class ComputeCmdsTest(unittest.TestCase):
42
+ def testGetProjectGeneratesCorrectRequest(self):
43
+ flag_values = copy.deepcopy(FLAGS)
44
+
45
+ command = project_cmds.GetProject('getproject', flag_values)
46
+
47
+ expected_project = 'test_project'
48
+ flag_values.project = expected_project
49
+
50
+ command.SetFlags(flag_values)
51
+ command.SetApi(mock_api.MockApi())
52
+
53
+ result = command.Handle()
54
+
55
+ self.assertEqual(result['project'], expected_project)
56
+
57
+ def testSetCommonInstanceMetadataGeneratesCorrectRequest(self):
58
+
59
+ class SetCommonInstanceMetadata(object):
60
+
61
+ def __call__(self, project, body):
62
+ self._project = project
63
+ self._body = body
64
+ return self
65
+
66
+ def execute(self):
67
+ return {'project': self._project, 'body': self._body}
68
+
69
+ flag_values = copy.deepcopy(FLAGS)
70
+ command = project_cmds.SetCommonInstanceMetadata(
71
+ 'setcommoninstancemetadata', flag_values)
72
+
73
+ expected_project = 'test_project'
74
+ flag_values.project = expected_project
75
+ flag_values.service_version = 'v1beta13'
76
+ with tempfile.NamedTemporaryFile() as metadata_file:
77
+ metadata_file.write('foo:bar')
78
+ metadata_file.flush()
79
+ flag_values.metadata_from_file = ['sshKeys:%s' % metadata_file.name]
80
+
81
+ command.SetFlags(flag_values)
82
+ command.SetApi(mock_api.MockApi())
83
+ command._projects_api.get = mock_api.CommandExecutor(
84
+ {'commonInstanceMetadata': [{'key': 'sshKeys', 'value': ''}]})
85
+ command._projects_api.setCommonInstanceMetadata = (
86
+ SetCommonInstanceMetadata())
87
+
88
+ result = command.Handle()
89
+ self.assertEquals(expected_project, result['project'])
90
+ self.assertEquals(
91
+ {'kind': 'compute#metadata',
92
+ 'items': [{'key': 'sshKeys', 'value': 'foo:bar'}]},
93
+ result['body'])
94
+
95
+ def testSetCommonInstanceMetadataChecksForOverwrites(self):
96
+ flag_values = copy.deepcopy(FLAGS)
97
+ command = project_cmds.SetCommonInstanceMetadata(
98
+ 'setcommoninstancemetadata', flag_values)
99
+
100
+ expected_project = 'test_project'
101
+ flag_values.project = expected_project
102
+ flag_values.service_version = 'v1beta13'
103
+ command.SetFlags(flag_values)
104
+ command.SetApi(mock_api.MockApi())
105
+ command._projects_api.get = mock_api.CommandExecutor(
106
+ {'commonInstanceMetadata': [{'key': 'sshKeys', 'value': 'foo:bar'}]})
107
+
108
+ self.assertRaises(command_base.CommandError, command.Handle)
109
+
110
+ if __name__ == '__main__':
111
+ unittest.main()
@@ -0,0 +1,61 @@
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
+ """The Google API scopes used by Google Compute Engine."""
16
+
17
+
18
+
19
+ USER_INFO_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
20
+ COMPUTE_RW_SCOPE = 'https://www.googleapis.com/auth/compute'
21
+ COMPUTE_RO_SCOPE = 'https://www.googleapis.com/auth/compute.readonly'
22
+ STORAGE_R_SCOPE = 'https://www.googleapis.com/auth/devstorage.read_only'
23
+ STORAGE_W_SCOPE = 'https://www.googleapis.com/auth/devstorage.write_only'
24
+ STORAGE_RW_SCOPE = (
25
+ 'https://www.googleapis.com/auth/devstorage.read_write')
26
+ STORAGE_FULL_SCOPE = 'https://www.googleapis.com/auth/devstorage.full_control'
27
+ DEFAULT_AUTH_SCOPES = [
28
+ COMPUTE_RW_SCOPE, COMPUTE_RO_SCOPE,
29
+ # USER_INFO_SCOPE allows seeing who user authenticated as.
30
+ USER_INFO_SCOPE,
31
+ # Image commands use STORAGE access.
32
+ STORAGE_R_SCOPE, STORAGE_W_SCOPE, STORAGE_RW_SCOPE, STORAGE_FULL_SCOPE
33
+ ]
34
+
35
+ TASKQUEUE = 'https://www.googleapis.com/auth/taskqueue'
36
+ BIGQUERY = 'https://www.googleapis.com/auth/bigquery'
37
+ CLOUDSQL = 'https://www.googleapis.com/auth/sqlservice'
38
+
39
+ SCOPE_ALIASES = {
40
+ 'bigquery': BIGQUERY,
41
+ 'cloudsql': CLOUDSQL,
42
+ 'compute-ro': COMPUTE_RO_SCOPE,
43
+ 'compute-rw': COMPUTE_RW_SCOPE,
44
+ 'storage-full': STORAGE_FULL_SCOPE,
45
+ 'storage-ro': STORAGE_R_SCOPE,
46
+ 'storage-rw': STORAGE_RW_SCOPE,
47
+ 'storage-wo': STORAGE_W_SCOPE,
48
+ 'taskqueue': TASKQUEUE,
49
+ }
50
+
51
+
52
+ def ExpandScopeAliases(scopes):
53
+ """Expand a list of scope aliases if available.
54
+
55
+ Args:
56
+ scopes: a list of scopes and scope aliases
57
+
58
+ Returns:
59
+ a list of scopes
60
+ """
61
+ return [SCOPE_ALIASES.get(s, s) for s in scopes]
@@ -0,0 +1,50 @@
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
+ """Tests for scopes module."""
18
+
19
+
20
+
21
+ import path_initializer
22
+ path_initializer.InitializeSysPath()
23
+
24
+ import unittest
25
+ from gcutil import scopes
26
+
27
+
28
+ class ScopesTest(unittest.TestCase):
29
+ def testExpandPassthrough(self):
30
+ scopes_in = ['foo', 'bar', scopes.TASKQUEUE]
31
+ scopes_out = scopes.ExpandScopeAliases(scopes_in)
32
+ self.assertEqual(scopes_out, scopes_in)
33
+
34
+ def testExpandEmpty(self):
35
+ scopes_in = []
36
+ scopes_out = scopes.ExpandScopeAliases(scopes_in)
37
+ self.assertEqual(scopes_out, scopes_in)
38
+
39
+ def testExpandSingle(self):
40
+ scopes_in = ['compute-rw']
41
+ scopes_out = scopes.ExpandScopeAliases(scopes_in)
42
+ self.assertEqual(scopes_out, [scopes.COMPUTE_RW_SCOPE])
43
+
44
+ def testExpandMixed(self):
45
+ scopes_in = ['compute-rw', scopes.TASKQUEUE]
46
+ scopes_out = scopes.ExpandScopeAliases(scopes_in)
47
+ self.assertEqual(scopes_out, [scopes.COMPUTE_RW_SCOPE, scopes.TASKQUEUE])
48
+
49
+ if __name__ == '__main__':
50
+ unittest.main()
@@ -0,0 +1,276 @@
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 disk snapshots."""
16
+
17
+
18
+
19
+ import time
20
+
21
+
22
+ from google.apputils import appcommands
23
+ import gflags as flags
24
+
25
+ from gcutil import command_base
26
+ from gcutil import gcutil_logging
27
+
28
+
29
+ FLAGS = flags.FLAGS
30
+ LOGGER = gcutil_logging.LOGGER
31
+
32
+
33
+ class SnapshotCommand(command_base.GoogleComputeCommand):
34
+ """Base command for working with the snapshots collection."""
35
+
36
+ default_sort_field = 'name'
37
+ summary_fields = (('name', 'name'),
38
+ ('description', 'description'),
39
+ ('creation-time', 'creationTimestamp'),
40
+ ('status', 'status'),
41
+ ('disk-size-gb', 'diskSizeGb'),
42
+ ('source-disk', 'sourceDisk'))
43
+
44
+ detail_fields = (('name', 'name'),
45
+ ('description', 'description'),
46
+ ('creation-time', 'creationTimestamp'),
47
+ ('status', 'status'),
48
+ ('disk-size-gb', 'diskSizeGb'),
49
+ ('source-disk', 'sourceDisk'))
50
+
51
+ resource_collection_name = 'snapshots'
52
+
53
+ def __init__(self, name, flag_values):
54
+ super(SnapshotCommand, 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._snapshots_api = api.snapshots()
67
+ self._disks_api = api.disks()
68
+ self._zones_api = api.zones()
69
+
70
+ def _PrepareRequestArgs(self, snapshot_name, **other_args):
71
+ """Gets the dictionary of API method keyword arguments.
72
+
73
+ Args:
74
+ snapshot_name: The name of the snapshot.
75
+ **other_args: Keyword arguments that should be included in the request.
76
+
77
+ Returns:
78
+ Dictionary of keyword arguments that should be passed in the API call,
79
+ includes all keyword arguments passed in 'other_args' plus
80
+ common keys such as the name of the resource and the project.
81
+ """
82
+
83
+ kwargs = {
84
+ 'project': self._project,
85
+ 'snapshot': self.DenormalizeResourceName(snapshot_name)
86
+ }
87
+ for key, value in other_args.items():
88
+ kwargs[key] = value
89
+ return kwargs
90
+
91
+
92
+ class AddSnapshot(SnapshotCommand):
93
+ """Create a new persistent disk snapshot."""
94
+
95
+ positional_args = '<snapshot-name>'
96
+ status_field = 'status'
97
+ _TERMINAL_STATUS = ['READY', 'FAILED']
98
+
99
+ def __init__(self, name, flag_values):
100
+ super(AddSnapshot, self).__init__(name, flag_values)
101
+ flags.DEFINE_string('description',
102
+ '',
103
+ 'Snapshot description.',
104
+ flag_values=flag_values)
105
+ flags.DEFINE_string('source_disk',
106
+ None,
107
+ 'The source disk for this snapshot.',
108
+ flag_values=flag_values)
109
+ flags.DEFINE_string('zone',
110
+ None,
111
+ 'The zone of the disk.',
112
+ flag_values=flag_values)
113
+ flags.DEFINE_boolean('wait_until_complete',
114
+ False,
115
+ 'Whether the program should wait until the snapshot'
116
+ ' is complete.',
117
+ flag_values=flag_values)
118
+
119
+ def Handle(self, snapshot_name):
120
+ """Add the specified snapshot.
121
+
122
+ Args:
123
+ snapshot_name: The name of the snapshot to add
124
+
125
+ Returns:
126
+ The result of inserting the snapshot.
127
+ """
128
+ if not self._flags.source_disk:
129
+ disk = self._PromptForDisk()
130
+ if not disk:
131
+ raise command_base.CommandError(
132
+ 'You cannot create a snapshot if you have no disks.')
133
+ self._flags.source_disk = disk['name']
134
+
135
+ zone = 'unused'
136
+ if self._IsUsingAtLeastApiVersion('v1beta14'):
137
+ zone = self.GetZoneForResource(self._disks_api, self._flags.source_disk)
138
+
139
+ source_disk = self.NormalizePerZoneResourceName(
140
+ self._project,
141
+ zone,
142
+ 'disks',
143
+ self._flags.source_disk)
144
+
145
+ kwargs = {
146
+ 'project': self._project,
147
+ }
148
+
149
+ snapshot_resource = {
150
+ 'kind': self._GetResourceApiKind('snapshot'),
151
+ 'name': self.DenormalizeResourceName(snapshot_name),
152
+ 'description': self._flags.description,
153
+ 'sourceDisk': source_disk
154
+ }
155
+
156
+ kwargs['body'] = snapshot_resource
157
+ snapshot_request = self._snapshots_api.insert(**kwargs)
158
+
159
+ result = snapshot_request.execute()
160
+
161
+ if self._flags.wait_until_complete:
162
+ result = self.WaitForOperation(self._flags, time, result)
163
+ if not result.get('error'):
164
+ result = self._InternalGetSnapshot(snapshot_name)
165
+ result = self._WaitUntilSnapshotIsComplete(result, snapshot_name)
166
+
167
+ return result
168
+
169
+ def _InternalGetSnapshot(self, snapshot_name):
170
+ """A simple implementation of getting current snapshot state.
171
+
172
+ Args:
173
+ snapshot_name: the name of the snapshot to get.
174
+
175
+ Returns:
176
+ Json containing full snapshot information.
177
+ """
178
+ snapshot_request = self._snapshots_api.get(
179
+ **self._PrepareRequestArgs(snapshot_name))
180
+ return snapshot_request.execute()
181
+
182
+ def _WaitUntilSnapshotIsComplete(self, result, snapshot_name):
183
+ """Waits for the snapshot to complete.
184
+
185
+ Periodically polls the server for current snapshot status. Exits if the
186
+ status of the snapshot is READY or FAILED or the maximum waiting
187
+ timeout has been reached. In both cases returns the last known snapshot
188
+ details.
189
+
190
+ Args:
191
+ result: the current state of the snapshot.
192
+ snapshot_name: the name of the snapshot to watch.
193
+
194
+ Returns:
195
+ Json containing full snapshot information.
196
+ """
197
+ current_status = result[self.status_field]
198
+ start_time = time.time()
199
+ LOGGER.info('Will wait for snapshot to complete for: %d seconds.',
200
+ self._flags.max_wait_time)
201
+ while (time.time() - start_time < self._flags.max_wait_time and
202
+ current_status not in self._TERMINAL_STATUS):
203
+ LOGGER.info(
204
+ 'Waiting for snapshot. Current status: %s. Sleeping for %ss.',
205
+ current_status, self._flags.sleep_between_polls)
206
+ time.sleep(self._flags.sleep_between_polls)
207
+ result = self._InternalGetSnapshot(snapshot_name)
208
+ current_status = result[self.status_field]
209
+ if current_status not in self._TERMINAL_STATUS:
210
+ LOGGER.warn('Timeout reached. Snapshot %s has not yet completed.',
211
+ snapshot_name)
212
+ return result
213
+
214
+
215
+ class GetSnapshot(SnapshotCommand):
216
+ """Get a machine snapshot."""
217
+
218
+ positional_args = '<snapshot-name>'
219
+
220
+ def __init__(self, name, flag_values):
221
+ super(GetSnapshot, self).__init__(name, flag_values)
222
+
223
+ def Handle(self, snapshot_name):
224
+ """Get the specified snapshot.
225
+
226
+ Args:
227
+ snapshot_name: The name of the snapshot to get
228
+
229
+ Returns:
230
+ The result of getting the snapshot.
231
+ """
232
+ snapshot_request = self._snapshots_api.get(
233
+ **self._PrepareRequestArgs(snapshot_name))
234
+
235
+ return snapshot_request.execute()
236
+
237
+
238
+ class DeleteSnapshot(SnapshotCommand):
239
+ """Delete one or more machine snapshots."""
240
+
241
+ positional_args = '<snapshot-name>'
242
+ safety_prompt = 'Delete snapshot'
243
+
244
+ def __init__(self, name, flag_values):
245
+ super(DeleteSnapshot, self).__init__(name, flag_values)
246
+
247
+ def Handle(self, *snapshot_names):
248
+ """Delete the specified snapshots.
249
+
250
+ Args:
251
+ *snapshot_names: The names of the snapshots to delete
252
+
253
+ Returns:
254
+ Tuple (results, exceptions) - results of deleting the snapshots.
255
+ """
256
+ requests = []
257
+ for snapshot_name in snapshot_names:
258
+ requests.append(self._snapshots_api.delete(
259
+ **self._PrepareRequestArgs(snapshot_name)))
260
+ results, exceptions = self.ExecuteRequests(requests)
261
+ return self.MakeListResult(results, 'operationList'), exceptions
262
+
263
+
264
+ class ListSnapshots(SnapshotCommand, command_base.GoogleComputeListCommand):
265
+ """List the machine snapshots for a project."""
266
+
267
+ def ListFunc(self):
268
+ """Returns the function for listing snapshots."""
269
+ return self._snapshots_api.list
270
+
271
+
272
+ def AddCommands():
273
+ appcommands.AddCmd('addsnapshot', AddSnapshot)
274
+ appcommands.AddCmd('getsnapshot', GetSnapshot)
275
+ appcommands.AddCmd('deletesnapshot', DeleteSnapshot)
276
+ appcommands.AddCmd('listsnapshots', ListSnapshots)