startapp 0.1.6

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 (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