startapp 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/COPYRIGHT +1 -0
  3. data/LICENSE +11 -0
  4. data/README.md +95 -0
  5. data/Rakefile +6 -0
  6. data/autocomplete/rhc_bash +1672 -0
  7. data/bin/app +37 -0
  8. data/conf/express.conf +8 -0
  9. data/features/assets/deploy.tar.gz +0 -0
  10. data/features/core_feature.rb +191 -0
  11. data/features/deployments_feature.rb +129 -0
  12. data/features/domains_feature.rb +58 -0
  13. data/features/keys_feature.rb +37 -0
  14. data/features/members_feature.rb +166 -0
  15. data/lib/rhc/auth/basic.rb +64 -0
  16. data/lib/rhc/auth/token.rb +102 -0
  17. data/lib/rhc/auth/token_store.rb +53 -0
  18. data/lib/rhc/auth.rb +5 -0
  19. data/lib/rhc/autocomplete.rb +66 -0
  20. data/lib/rhc/autocomplete_templates/bash.erb +39 -0
  21. data/lib/rhc/cartridge_helpers.rb +118 -0
  22. data/lib/rhc/cli.rb +40 -0
  23. data/lib/rhc/command_runner.rb +185 -0
  24. data/lib/rhc/commands/account.rb +25 -0
  25. data/lib/rhc/commands/alias.rb +124 -0
  26. data/lib/rhc/commands/app.rb +726 -0
  27. data/lib/rhc/commands/apps.rb +20 -0
  28. data/lib/rhc/commands/authorization.rb +115 -0
  29. data/lib/rhc/commands/base.rb +174 -0
  30. data/lib/rhc/commands/cartridge.rb +329 -0
  31. data/lib/rhc/commands/clone.rb +66 -0
  32. data/lib/rhc/commands/configure.rb +20 -0
  33. data/lib/rhc/commands/create.rb +100 -0
  34. data/lib/rhc/commands/delete.rb +19 -0
  35. data/lib/rhc/commands/deploy.rb +32 -0
  36. data/lib/rhc/commands/deployment.rb +82 -0
  37. data/lib/rhc/commands/domain.rb +172 -0
  38. data/lib/rhc/commands/env.rb +142 -0
  39. data/lib/rhc/commands/force_stop.rb +17 -0
  40. data/lib/rhc/commands/git_clone.rb +34 -0
  41. data/lib/rhc/commands/logout.rb +51 -0
  42. data/lib/rhc/commands/logs.rb +21 -0
  43. data/lib/rhc/commands/member.rb +148 -0
  44. data/lib/rhc/commands/port_forward.rb +197 -0
  45. data/lib/rhc/commands/reload.rb +17 -0
  46. data/lib/rhc/commands/restart.rb +17 -0
  47. data/lib/rhc/commands/scp.rb +54 -0
  48. data/lib/rhc/commands/server.rb +40 -0
  49. data/lib/rhc/commands/setup.rb +60 -0
  50. data/lib/rhc/commands/show.rb +43 -0
  51. data/lib/rhc/commands/snapshot.rb +137 -0
  52. data/lib/rhc/commands/ssh.rb +51 -0
  53. data/lib/rhc/commands/sshkey.rb +97 -0
  54. data/lib/rhc/commands/start.rb +17 -0
  55. data/lib/rhc/commands/stop.rb +17 -0
  56. data/lib/rhc/commands/tail.rb +47 -0
  57. data/lib/rhc/commands/threaddump.rb +14 -0
  58. data/lib/rhc/commands/tidy.rb +17 -0
  59. data/lib/rhc/commands.rb +396 -0
  60. data/lib/rhc/config.rb +321 -0
  61. data/lib/rhc/context_helper.rb +121 -0
  62. data/lib/rhc/core_ext.rb +202 -0
  63. data/lib/rhc/coverage_helper.rb +33 -0
  64. data/lib/rhc/deployment_helpers.rb +111 -0
  65. data/lib/rhc/exceptions.rb +256 -0
  66. data/lib/rhc/git_helpers.rb +106 -0
  67. data/lib/rhc/help_formatter.rb +55 -0
  68. data/lib/rhc/helpers.rb +481 -0
  69. data/lib/rhc/highline_extensions.rb +479 -0
  70. data/lib/rhc/json.rb +51 -0
  71. data/lib/rhc/output_helpers.rb +260 -0
  72. data/lib/rhc/rest/activation.rb +11 -0
  73. data/lib/rhc/rest/alias.rb +42 -0
  74. data/lib/rhc/rest/api.rb +87 -0
  75. data/lib/rhc/rest/application.rb +348 -0
  76. data/lib/rhc/rest/attributes.rb +36 -0
  77. data/lib/rhc/rest/authorization.rb +8 -0
  78. data/lib/rhc/rest/base.rb +79 -0
  79. data/lib/rhc/rest/cartridge.rb +162 -0
  80. data/lib/rhc/rest/client.rb +650 -0
  81. data/lib/rhc/rest/deployment.rb +18 -0
  82. data/lib/rhc/rest/domain.rb +98 -0
  83. data/lib/rhc/rest/environment_variable.rb +15 -0
  84. data/lib/rhc/rest/gear_group.rb +16 -0
  85. data/lib/rhc/rest/httpclient.rb +145 -0
  86. data/lib/rhc/rest/key.rb +44 -0
  87. data/lib/rhc/rest/membership.rb +105 -0
  88. data/lib/rhc/rest/mock.rb +1042 -0
  89. data/lib/rhc/rest/user.rb +32 -0
  90. data/lib/rhc/rest.rb +148 -0
  91. data/lib/rhc/scp_helpers.rb +27 -0
  92. data/lib/rhc/ssh_helpers.rb +380 -0
  93. data/lib/rhc/tar_gz.rb +51 -0
  94. data/lib/rhc/usage_templates/command_help.erb +51 -0
  95. data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
  96. data/lib/rhc/usage_templates/help.erb +61 -0
  97. data/lib/rhc/usage_templates/missing_help.erb +1 -0
  98. data/lib/rhc/usage_templates/options_help.erb +12 -0
  99. data/lib/rhc/vendor/okjson.rb +600 -0
  100. data/lib/rhc/vendor/parseconfig.rb +178 -0
  101. data/lib/rhc/vendor/sshkey.rb +253 -0
  102. data/lib/rhc/vendor/zliby.rb +628 -0
  103. data/lib/rhc/version.rb +5 -0
  104. data/lib/rhc/wizard.rb +637 -0
  105. data/lib/rhc.rb +34 -0
  106. data/spec/coverage_helper.rb +82 -0
  107. data/spec/direct_execution_helper.rb +339 -0
  108. data/spec/keys/example.pem +23 -0
  109. data/spec/keys/example_private.pem +27 -0
  110. data/spec/keys/server.pem +19 -0
  111. data/spec/rest_spec_helper.rb +31 -0
  112. data/spec/rhc/assets/cert.crt +22 -0
  113. data/spec/rhc/assets/cert_key_rsa +27 -0
  114. data/spec/rhc/assets/empty.txt +0 -0
  115. data/spec/rhc/assets/env_vars.txt +7 -0
  116. data/spec/rhc/assets/env_vars_2.txt +1 -0
  117. data/spec/rhc/assets/foo.txt +1 -0
  118. data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
  119. data/spec/rhc/assets/targz_sample.tar.gz +0 -0
  120. data/spec/rhc/auth_spec.rb +442 -0
  121. data/spec/rhc/cli_spec.rb +186 -0
  122. data/spec/rhc/command_spec.rb +435 -0
  123. data/spec/rhc/commands/account_spec.rb +42 -0
  124. data/spec/rhc/commands/alias_spec.rb +333 -0
  125. data/spec/rhc/commands/app_spec.rb +777 -0
  126. data/spec/rhc/commands/apps_spec.rb +39 -0
  127. data/spec/rhc/commands/authorization_spec.rb +157 -0
  128. data/spec/rhc/commands/cartridge_spec.rb +665 -0
  129. data/spec/rhc/commands/clone_spec.rb +41 -0
  130. data/spec/rhc/commands/deployment_spec.rb +327 -0
  131. data/spec/rhc/commands/domain_spec.rb +401 -0
  132. data/spec/rhc/commands/env_spec.rb +493 -0
  133. data/spec/rhc/commands/git_clone_spec.rb +102 -0
  134. data/spec/rhc/commands/logout_spec.rb +86 -0
  135. data/spec/rhc/commands/member_spec.rb +247 -0
  136. data/spec/rhc/commands/port_forward_spec.rb +217 -0
  137. data/spec/rhc/commands/scp_spec.rb +77 -0
  138. data/spec/rhc/commands/server_spec.rb +69 -0
  139. data/spec/rhc/commands/setup_spec.rb +118 -0
  140. data/spec/rhc/commands/snapshot_spec.rb +179 -0
  141. data/spec/rhc/commands/ssh_spec.rb +163 -0
  142. data/spec/rhc/commands/sshkey_spec.rb +188 -0
  143. data/spec/rhc/commands/tail_spec.rb +81 -0
  144. data/spec/rhc/commands/threaddump_spec.rb +84 -0
  145. data/spec/rhc/config_spec.rb +407 -0
  146. data/spec/rhc/helpers_spec.rb +531 -0
  147. data/spec/rhc/highline_extensions_spec.rb +314 -0
  148. data/spec/rhc/json_spec.rb +30 -0
  149. data/spec/rhc/rest_application_spec.rb +258 -0
  150. data/spec/rhc/rest_client_spec.rb +752 -0
  151. data/spec/rhc/rest_spec.rb +740 -0
  152. data/spec/rhc/targz_spec.rb +55 -0
  153. data/spec/rhc/wizard_spec.rb +756 -0
  154. data/spec/spec_helper.rb +575 -0
  155. data/spec/wizard_spec_helper.rb +330 -0
  156. metadata +469 -0
@@ -0,0 +1,256 @@
1
+ module RHC
2
+ class Exception < StandardError
3
+ attr_reader :code
4
+ def initialize(message=nil, code=1)
5
+ super(message)
6
+ @code = code
7
+ end
8
+ end
9
+
10
+ class ConfirmationError < Exception
11
+ def initialize(message="This action requires the --confirm option (or entering 'yes' at a prompt) to run.", code=1)
12
+ super(message, code)
13
+ end
14
+ end
15
+
16
+ class CartridgeNotFoundException < Exception
17
+ def initialize(message="Cartridge not found")
18
+ super message, 154
19
+ end
20
+ end
21
+
22
+ class AliasNotFoundException < Exception
23
+ def initialize(message="Alias not found")
24
+ super message, 156
25
+ end
26
+ end
27
+
28
+ class MultipleCartridgesException < Exception
29
+ def initialize(message="Multiple cartridge found")
30
+ super message, 155
31
+ end
32
+ end
33
+
34
+ class EnvironmentVariableNotFoundException < Exception
35
+ def initialize(message="Environment variable not found")
36
+ super message, 157
37
+ end
38
+ end
39
+
40
+ class EnvironmentVariablesNotSupportedException < Exception
41
+ def initialize(message="Server does not support environment variables")
42
+ super message, 158
43
+ end
44
+ end
45
+
46
+ class EnvironmentVariableNotProvidedException < Exception
47
+ def initialize(message="Environment variable not provided")
48
+ super message, 159
49
+ end
50
+ end
51
+
52
+ class JenkinsNotInstalledOnServer < Exception
53
+ def initialize(message="There is no installed cartridge that exposes Jenkins")
54
+ super message, 160
55
+ end
56
+ end
57
+
58
+ class KeyNotFoundException < Exception
59
+ def initialize(message="SSHKey not found")
60
+ super message, 118
61
+ end
62
+ end
63
+
64
+ class GitException < Exception
65
+ def initialize(message="Git returned an error")
66
+ super message, 216
67
+ end
68
+ end
69
+
70
+ class GitPermissionDenied < GitException; end
71
+ class GitDirectoryExists < GitException; end
72
+
73
+ class DeprecatedError < RuntimeError; end
74
+
75
+ class KeyFileNotExistentException < Exception
76
+ def initialize(message="SSH Key file not found")
77
+ super message, 128
78
+ end
79
+ end
80
+
81
+ class KeyFileAccessDeniedException < Exception
82
+ def initialize(message = "Insufficient acces to SSH Key file")
83
+ super message, 128
84
+ end
85
+ end
86
+
87
+ class KeyDataInvalidException < Exception
88
+ def initialize(message = "SSH Key file contains invalid data")
89
+ super message, 128
90
+ end
91
+ end
92
+
93
+ class PermissionDeniedException < Exception
94
+ def initialize(message="Permission denied")
95
+ super message, 129
96
+ end
97
+ end
98
+
99
+ class NoPortsToForwardException < Exception
100
+ def initialize(message="No available ports to forward")
101
+ super message, 102
102
+ end
103
+ end
104
+
105
+ class PortForwardFailedException < Exception
106
+ def initialize(message="Port forward failed")
107
+ super message, 1
108
+ end
109
+ end
110
+
111
+ class SnapshotSaveException < Exception
112
+ def initialize(message="Error trying to save snapshot")
113
+ super message, 130
114
+ end
115
+ end
116
+
117
+ class SnapshotRestoreException < Exception
118
+ def initialize(message="Error trying to restore snapshot")
119
+ super message, 130
120
+ end
121
+ end
122
+
123
+ class DeploymentNotFoundException < Exception
124
+ def initialize(message="Deployment not found")
125
+ super message, 131
126
+ end
127
+ end
128
+
129
+ class DeploymentsNotSupportedException < Exception
130
+ def initialize(message="The server does not support deployments")
131
+ super message, 132
132
+ end
133
+ end
134
+
135
+ class IncompatibleDeploymentTypeException < Exception
136
+ def initialize(message="The artifact provided is not compatible with the app deployment type.")
137
+ super message, 133
138
+ end
139
+ end
140
+
141
+ class MissingScalingValueException < Exception
142
+ def initialize(message="Must provide either a min or max value for scaling")
143
+ super message
144
+ end
145
+ end
146
+
147
+ class CartridgeNotScalableException < Exception
148
+ def initialize(message="Cartridge is not scalable")
149
+ super message
150
+ end
151
+ end
152
+
153
+ class ConnectionFailed < Exception
154
+ end
155
+
156
+ class SSHAuthenticationFailed < Exception
157
+ def initialize(host, user)
158
+ super "Authentication to server #{host} with user #{user} failed"
159
+ end
160
+ end
161
+
162
+ class SSHConnectionRefused < ConnectionFailed
163
+ def initialize(host, user)
164
+ super "The server #{host} refused a connection with user #{user}. The application may be unavailable.", 1
165
+ end
166
+ end
167
+
168
+ class SSHCommandFailed < Exception
169
+ def initialize(exit_status, message=nil)
170
+ super message || "SSH command finished with exit status = #{exit_status}", 133
171
+ end
172
+ end
173
+
174
+ class AdditionalStorageArgumentsException < Exception
175
+ def initialize(message="Only one storage action can be performed at a time.")
176
+ super message, 1
177
+ end
178
+ end
179
+
180
+ class AdditionalStorageValueException < Exception
181
+ def initialize(message="The amount format must be a number, optionally followed by 'GB' (ex.: 5GB)")
182
+ super message, 1
183
+ end
184
+ end
185
+
186
+ class AdditionalStorageRemoveException < Exception
187
+ def initialize(message="The amount of additional storage to be removed exceeds the total amount in use. Add the -f flag to override.")
188
+ super message, 1
189
+ end
190
+ end
191
+
192
+ class ChangeMembersOnResourceNotSupported < Exception
193
+ def initialize(message="You can only add or remove members on a domain.")
194
+ super message, 1
195
+ end
196
+ end
197
+
198
+ class MembersNotSupported < Exception
199
+ def initialize(message="The server does not support adding or removing members.")
200
+ super message, 1
201
+ end
202
+ end
203
+
204
+ class UnsupportedError < Exception
205
+ def initialize(message="This operation is not supported by the server.")
206
+ super message, 1
207
+ end
208
+ end
209
+ class NoPerGearOperations < UnsupportedError
210
+ def initialize
211
+ super "The server does not support operations on individual gears."
212
+ end
213
+ end
214
+ class ServerAPINotSupportedException < UnsupportedError
215
+ def initialize(min_version, current_version)
216
+ super "The server does not support this command (requires #{min_version}, found #{current_version})."
217
+ end
218
+ end
219
+ class OperationNotSupportedException < UnsupportedError; end
220
+
221
+ class InvalidURIException < Exception
222
+ def initialize(uri)
223
+ super "Invalid URI specified: #{uri}"
224
+ end
225
+ end
226
+
227
+ class InvalidSSHExecutableException < Exception
228
+ def initialize(message="Invalid or missing SSH executable")
229
+ super message
230
+ end
231
+ end
232
+
233
+ class FileOrPathNotFound < Exception
234
+ def initialize(message="File, file path, or directory could not be found")
235
+ super message
236
+ end
237
+ end
238
+
239
+ class RemoteFileOrPathNotFound < FileOrPathNotFound
240
+ def initialize(message="Remote File, file path, or directory could not be found")
241
+ super message
242
+ end
243
+ end
244
+
245
+ class ArgumentNotValid < Exception
246
+ def initialize(message="Argument is not valid for this command")
247
+ super message
248
+ end
249
+ end
250
+
251
+ class NoDomainsForUser < Exception
252
+ def initialize(message="In order to deploy applications, you must create a domain with 'rhc setup' or 'rhc create-domain'.")
253
+ super message, 1
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,106 @@
1
+ require 'open4'
2
+ require 'fileutils'
3
+
4
+ module RHC
5
+ module GitHelpers
6
+ def git_cmd
7
+ "git"
8
+ end
9
+
10
+ def git_version
11
+ @git_version ||= `#{git_cmd} --version 2>&1`.strip #:nocov:
12
+ end
13
+
14
+ def has_git?
15
+ @has_git ||= begin
16
+ @git_version = nil
17
+ git_version
18
+ $?.success?
19
+ rescue
20
+ false
21
+ end
22
+ end
23
+
24
+ def git_clone_deploy_hooks(repo_dir)
25
+ debug "Deploy default hooks"
26
+ Dir.chdir(repo_dir) do |dir|
27
+ Dir.glob(".openshift/git_hooks/*") do |hook|
28
+ FileUtils.cp(hook, ".git/hooks/")
29
+ end
30
+ end
31
+ end
32
+
33
+ def git_clone_application(app)
34
+ repo_dir = options.repo || app.name
35
+
36
+ debug "Pulling new repo down"
37
+ dir = git_clone_repo(app.git_url, repo_dir)
38
+
39
+ debug "Configuring git repo"
40
+ Dir.chdir(repo_dir) do
41
+ git_config_set "rhc.app-id", app.id
42
+ git_config_set "rhc.app-name", app.name
43
+ git_config_set "rhc.domain-name", app.domain_id
44
+
45
+ git_remote_add("startapp", app.initial_git_url) if app.initial_git_url.present?
46
+ end
47
+
48
+ git_clone_deploy_hooks(repo_dir)
49
+
50
+ dir
51
+ end
52
+
53
+ def git_remote_add(remote_name, remote_url)
54
+ cmd = "#{git_cmd} remote add startapp \"#{remote_url}\""
55
+ debug "Running #{cmd} 2>&1"
56
+ output = %x[#{cmd} 2>&1]
57
+ raise RHC::GitException, "Error while adding startapp remote - #{output}" unless output.empty?
58
+ end
59
+
60
+ # :nocov: These all call external binaries so test them in cucumber
61
+ def git_config_get(key)
62
+ return nil unless has_git?
63
+
64
+ config_get_cmd = "#{git_cmd} config --get #{key}"
65
+ value = %x[#{config_get_cmd}].strip
66
+ debug "Git config '#{config_get_cmd}' returned '#{value}'"
67
+ value = nil if $?.exitstatus != 0 or value.empty?
68
+
69
+ value
70
+ end
71
+
72
+ def git_config_set(key, value)
73
+ unset_cmd = "#{git_cmd} config --unset-all #{key}"
74
+ config_cmd = "#{git_cmd} config --add #{key} #{value}"
75
+ debug "Adding #{key} = #{value} to git config"
76
+ commands = [unset_cmd, config_cmd]
77
+ commands.each do |cmd|
78
+ debug "Running #{cmd} 2>&1"
79
+ output = %x[#{cmd} 2>&1]
80
+ raise RHC::GitException, "Error while adding config values to git - #{output}" unless output.empty?
81
+ end
82
+ end
83
+ # :nocov:
84
+
85
+ def git_clone_repo(git_url, repo_dir)
86
+ # quote the repo to avoid input injection risk
87
+ destination = (repo_dir ? " \"#{repo_dir}\"" : "")
88
+ cmd = "#{git_cmd} clone #{git_url}#{destination}"
89
+ debug "Running #{cmd}"
90
+
91
+ status, stdout, stderr = run_with_tee(cmd)
92
+
93
+ if status != 0
94
+ case stderr
95
+ when /fatal: destination path '[^']*' already exists and is not an empty directory./
96
+ raise RHC::GitDirectoryExists, "The directory you are cloning into already exists."
97
+ when /^Permission denied \(.*?publickey.*?\).$/
98
+ raise RHC::GitPermissionDenied, "You don't have permission to access this repository. Check that your SSH public keys are correct."
99
+ else
100
+ raise RHC::GitException, "Unable to clone your repository. Called Git with: #{cmd}"
101
+ end
102
+ end
103
+ File.expand_path(repo_dir)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,55 @@
1
+ require 'commander/help_formatters/base'
2
+
3
+ module RHC
4
+ class HelpFormatter < Commander::HelpFormatter::Terminal
5
+ def template(name)
6
+ ERB.new(File.read(File.join(File.dirname(__FILE__), 'usage_templates', "#{name}.erb")), nil, '-')
7
+ end
8
+ def render
9
+ template(:help).result RunnerHelpBindings.new(@runner).get_binding
10
+ end
11
+ def render_command_syntax command
12
+ template(:command_syntax_help).result command.get_binding
13
+ end
14
+ def render_options runner
15
+ template(:options_help).result RunnerHelpBindings.new(runner).get_binding
16
+ end
17
+ end
18
+
19
+ class RunnerHelpBindings < SimpleDelegator
20
+ include RHC::Helpers
21
+
22
+ def commands
23
+ __getobj__.instance_variable_get(:@commands)
24
+ end
25
+
26
+ def get_binding
27
+ binding
28
+ end
29
+ end
30
+
31
+ class CommandHelpBindings
32
+ include RHC::Helpers
33
+
34
+ def initialize(command, instance_commands, runner)
35
+ @command = command
36
+ @actions =
37
+ if command.root?
38
+ instance_commands.sort_by{ |c| c[0] }.collect do |command_name, command_class|
39
+ next if command_class.summary.nil?
40
+ m = /^#{command.name}[\-]([^ ]+)/.match(command_name)
41
+ # if we have a match and it is not an alias then we can use it
42
+ m and command_name == command_class.name ? {:name => m[1], :summary => command_class.summary || ""} : nil
43
+ end
44
+ else
45
+ []
46
+ end
47
+ @actions.compact!
48
+ @global_options = runner.options
49
+ @runner = runner
50
+ end
51
+ def program(*args)
52
+ @runner.program *args
53
+ end
54
+ end
55
+ end