cf 0.6.1.rc9 → 0.6.1.rc10

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 (79) hide show
  1. data/lib/cf.rb +4 -0
  2. data/lib/cf/cli.rb +8 -3
  3. data/lib/cf/version.rb +1 -1
  4. data/lib/console/README.md +16 -0
  5. data/lib/console/console.rb +187 -0
  6. data/lib/console/plugin.rb +30 -0
  7. data/lib/manifests/README.md +13 -0
  8. data/lib/manifests/errors.rb +35 -0
  9. data/lib/manifests/loader.rb +31 -0
  10. data/lib/manifests/loader/builder.rb +39 -0
  11. data/lib/manifests/loader/normalizer.rb +145 -0
  12. data/lib/manifests/loader/resolver.rb +79 -0
  13. data/lib/manifests/manifests.rb +304 -0
  14. data/lib/manifests/plugin.rb +141 -0
  15. data/lib/tunnel/README.md +29 -0
  16. data/lib/tunnel/helper-app/Gemfile +11 -0
  17. data/lib/tunnel/helper-app/Gemfile.lock +48 -0
  18. data/lib/tunnel/helper-app/server.rb +43 -0
  19. data/lib/tunnel/plugin.rb +183 -0
  20. data/lib/tunnel/tunnel.rb +305 -0
  21. data/spec/assets/rails328_ruby187_app/Gemfile +39 -0
  22. data/spec/assets/rails328_ruby187_app/README.rdoc +261 -0
  23. data/spec/assets/rails328_ruby187_app/Rakefile +7 -0
  24. data/spec/assets/rails328_ruby187_app/app/assets/images/rails.png +0 -0
  25. data/spec/assets/rails328_ruby187_app/app/assets/javascripts/application.js +15 -0
  26. data/spec/assets/rails328_ruby187_app/app/assets/stylesheets/application.css +13 -0
  27. data/spec/assets/rails328_ruby187_app/app/controllers/application_controller.rb +3 -0
  28. data/spec/assets/rails328_ruby187_app/app/helpers/application_helper.rb +2 -0
  29. data/spec/assets/rails328_ruby187_app/app/views/layouts/application.html.erb +14 -0
  30. data/spec/assets/rails328_ruby187_app/config.ru +4 -0
  31. data/spec/assets/rails328_ruby187_app/config/application.rb +62 -0
  32. data/spec/assets/rails328_ruby187_app/config/boot.rb +6 -0
  33. data/spec/assets/rails328_ruby187_app/config/database.yml +25 -0
  34. data/spec/assets/rails328_ruby187_app/config/environment.rb +5 -0
  35. data/spec/assets/rails328_ruby187_app/config/environments/development.rb +37 -0
  36. data/spec/assets/rails328_ruby187_app/config/environments/production.rb +67 -0
  37. data/spec/assets/rails328_ruby187_app/config/environments/test.rb +37 -0
  38. data/spec/assets/rails328_ruby187_app/config/initializers/backtrace_silencers.rb +7 -0
  39. data/spec/assets/rails328_ruby187_app/config/initializers/inflections.rb +15 -0
  40. data/spec/assets/rails328_ruby187_app/config/initializers/mime_types.rb +5 -0
  41. data/spec/assets/rails328_ruby187_app/config/initializers/secret_token.rb +7 -0
  42. data/spec/assets/rails328_ruby187_app/config/initializers/session_store.rb +8 -0
  43. data/spec/assets/rails328_ruby187_app/config/initializers/wrap_parameters.rb +14 -0
  44. data/spec/assets/rails328_ruby187_app/config/locales/en.yml +5 -0
  45. data/spec/assets/rails328_ruby187_app/config/routes.rb +58 -0
  46. data/spec/assets/rails328_ruby187_app/db/seeds.rb +7 -0
  47. data/spec/assets/rails328_ruby187_app/doc/README_FOR_APP +2 -0
  48. data/spec/assets/rails328_ruby187_app/manifest.yml +7 -0
  49. data/spec/assets/rails328_ruby187_app/public/404.html +26 -0
  50. data/spec/assets/rails328_ruby187_app/public/422.html +26 -0
  51. data/spec/assets/rails328_ruby187_app/public/500.html +25 -0
  52. data/spec/assets/rails328_ruby187_app/public/assets/application-7270767b2a9e9fff880aa5de378ca791.css +0 -0
  53. data/spec/assets/rails328_ruby187_app/public/assets/application-7270767b2a9e9fff880aa5de378ca791.css.gz +0 -0
  54. data/spec/assets/rails328_ruby187_app/public/assets/application-ccab98dc1abdf097c0af693e20aed861.js +17 -0
  55. data/spec/assets/rails328_ruby187_app/public/assets/application-ccab98dc1abdf097c0af693e20aed861.js.gz +0 -0
  56. data/spec/assets/rails328_ruby187_app/public/assets/application.css +0 -0
  57. data/spec/assets/rails328_ruby187_app/public/assets/application.css.gz +0 -0
  58. data/spec/assets/rails328_ruby187_app/public/assets/application.js +17 -0
  59. data/spec/assets/rails328_ruby187_app/public/assets/application.js.gz +0 -0
  60. data/spec/assets/rails328_ruby187_app/public/assets/manifest.yml +4 -0
  61. data/spec/assets/rails328_ruby187_app/public/assets/rails-be8732dac73d845ac5b142c8fb5f9fb0.png +0 -0
  62. data/spec/assets/rails328_ruby187_app/public/assets/rails.png +0 -0
  63. data/spec/assets/rails328_ruby187_app/public/favicon.ico +0 -0
  64. data/spec/assets/rails328_ruby187_app/public/index.html +241 -0
  65. data/spec/assets/rails328_ruby187_app/public/robots.txt +5 -0
  66. data/spec/assets/rails328_ruby187_app/script/rails +6 -0
  67. data/spec/assets/rails328_ruby187_app/test/performance/browsing_test.rb +12 -0
  68. data/spec/assets/rails328_ruby187_app/test/test_helper.rb +13 -0
  69. data/spec/cf/cli/app/stats_spec.rb +20 -20
  70. data/spec/cf/cli_spec.rb +37 -18
  71. data/spec/console/console_spec.rb +189 -0
  72. data/spec/features/push_flow_spec.rb +1 -1
  73. data/spec/manifests/errors_spec.rb +43 -0
  74. data/spec/manifests/loader/builder_spec.rb +80 -0
  75. data/spec/manifests/loader/normalizer_spec.rb +158 -0
  76. data/spec/manifests/manifests_spec.rb +309 -0
  77. data/spec/manifests/plugin_spec.rb +362 -0
  78. data/spec/tunnel/plugin_spec.rb +31 -0
  79. metadata +184 -25
data/lib/cf.rb CHANGED
@@ -6,3 +6,7 @@ command_files = "../cf/cli/{app,route,domain,organization,space,service,start,us
6
6
  Dir[File.expand_path(command_files, __FILE__)].each do |file|
7
7
  require file unless File.basename(file) == 'base.rb'
8
8
  end
9
+
10
+ require "tunnel/plugin"
11
+ require "console/plugin"
12
+ require "manifests/plugin"
data/lib/cf/cli.rb CHANGED
@@ -26,8 +26,11 @@ module CF
26
26
  option :help, :desc => "Show command usage", :alias => "-h",
27
27
  :default => false
28
28
 
29
- option :proxy, :desc => "Run this command as another user (admin)", :alias => "-u",
30
- :value => :email
29
+ option :http_proxy, :desc => "Connect though an http proxy server", :alias => "--http-proxy",
30
+ :value => :http_proxy
31
+
32
+ option :https_proxy, :desc => "Connect though an https proxy server", :alias => "--https-proxy",
33
+ :value => :https_proxy
31
34
 
32
35
  option :version, :desc => "Print version number", :alias => "-v",
33
36
  :default => false
@@ -380,9 +383,11 @@ module CF
380
383
  token = info[:token] && CFoundry::AuthToken.from_hash(info)
381
384
 
382
385
  fail "V1 targets are no longer supported." if info[:version] == 1
383
- fail "User switching not implemented." if input[:proxy]
384
386
 
385
387
  @@client = CFoundry::V2::Client.new(target, token)
388
+
389
+ @@client.http_proxy = input[:http_proxy] || ENV['HTTP_PROXY'] || ENV['http_proxy']
390
+ @@client.https_proxy = input[:https_proxy] || ENV['HTTPS_PROXY'] || ENV['https_proxy']
386
391
  @@client.trace = input[:trace]
387
392
 
388
393
  uri = URI.parse(target)
data/lib/cf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CF
2
- VERSION = "0.6.1.rc9".freeze
2
+ VERSION = "0.6.1.rc10".freeze
3
3
  end
@@ -0,0 +1,16 @@
1
+ [![Build Status](https://travis-ci.org/cloudfoundry/console-cf-plugin.png)](https://travis-ci.org/cloudfoundry/console-cf-plugin)
2
+ [![Gem Version](https://badge.fury.io/rb/console-cf-plugin.png)](http://badge.fury.io/rb/console-cf-plugin)
3
+
4
+ ## Console
5
+ ### Info
6
+ This plugin lets you connect to a Cloud Foundry application via telnet.
7
+
8
+ ### Installation
9
+ ```
10
+ gem install console-cf-plugin
11
+ ```
12
+
13
+ ### Usage
14
+ ```
15
+ console APP Open a console connected to your app
16
+ ```
@@ -0,0 +1,187 @@
1
+ require "net/telnet"
2
+ require "readline"
3
+
4
+ require "tunnel/tunnel"
5
+
6
+ class CFConsole < CFTunnel
7
+ def initialize(client, app, port = 10000)
8
+ @client = client
9
+ @app = app
10
+ @port = port
11
+ end
12
+
13
+ def get_connection_info(auth)
14
+ instances = @app.instances
15
+ if instances.empty?
16
+ raise "App has no running instances; try starting it."
17
+ end
18
+
19
+ unless console = instances[0].console
20
+ raise "App does not have console access; try restarting it."
21
+ end
22
+
23
+ { "hostname" => console[:ip],
24
+ "port" => console[:port]
25
+ }
26
+ end
27
+
28
+ def get_credentials
29
+ YAML.load(@app.file("app", "cf-rails-console", ".consoleaccess"))
30
+ end
31
+
32
+ def start_console
33
+ prompt = login
34
+
35
+ init_readline
36
+
37
+ run_console prompt
38
+ end
39
+
40
+ def login(auth = get_credentials)
41
+ if !auth["username"] || !auth["password"]
42
+ raise "Unable to verify console credentials."
43
+ end
44
+
45
+ @telnet = telnet_client
46
+
47
+ prompt = nil
48
+ err_msg = "Login attempt timed out."
49
+
50
+ 5.times do
51
+ begin
52
+ results = @telnet.login(
53
+ "Name" => auth["username"],
54
+ "Password" => auth["password"])
55
+
56
+ lines = results.sub("Login: Password: ", "").split("\n")
57
+
58
+ last_line = lines.pop
59
+
60
+ if last_line =~ /[$%#>] \z/n
61
+ prompt = last_line
62
+ elsif last_line =~ /Login failed/
63
+ err_msg = last_line
64
+ end
65
+
66
+ break
67
+
68
+ rescue TimeoutError
69
+ sleep 1
70
+
71
+ rescue EOFError
72
+ # This may happen if we login right after app starts
73
+ close_console
74
+ sleep 5
75
+ @telnet = telnet_client
76
+ end
77
+ end
78
+
79
+ unless prompt
80
+ close_console
81
+ raise err_msg
82
+ end
83
+
84
+ prompt
85
+ end
86
+
87
+ private
88
+
89
+ def init_readline
90
+ if Readline.respond_to?("basic_word_break_characters=")
91
+ Readline.basic_word_break_characters= " \t\n`><=;|&{("
92
+ end
93
+
94
+ Readline.completion_append_character = nil
95
+
96
+ # Assumes that sending a String ending with tab will return a non-empty
97
+ # String of comma-separated completion options, terminated by a new line
98
+ # For example, "app.\t" might result in "to_s,nil?,etc\n"
99
+ Readline.completion_proc = proc do |s|
100
+ console_tab_completion_data(s)
101
+ end
102
+ end
103
+
104
+ def run_console(prompt)
105
+ prev = trap("INT") { |x| exit_console; prev.call(x); exit }
106
+ prev = trap("TERM") { |x| exit_console; prev.call(x); exit }
107
+
108
+ loop do
109
+ cmd = readline_with_history(prompt)
110
+
111
+ if cmd == nil
112
+ exit_console
113
+ break
114
+ end
115
+
116
+ prompt = send_console_command_display_results(cmd, prompt)
117
+ end
118
+ end
119
+
120
+ def readline_with_history(prompt)
121
+ line = Readline::readline(prompt)
122
+
123
+ return if line == nil || line == 'quit' || line == 'exit'
124
+
125
+ if line !~ /^\s*$/ && Readline::HISTORY.to_a[-1] != line
126
+ Readline::HISTORY.push(line)
127
+ end
128
+
129
+ line
130
+ end
131
+
132
+ def send_console_command_display_results(cmd, prompt)
133
+ begin
134
+ lines = send_console_command cmd
135
+
136
+ # Assumes the last line is a prompt
137
+ prompt = lines.pop
138
+
139
+ lines.each do |line|
140
+ puts line if line != cmd
141
+ end
142
+
143
+ rescue TimeoutError
144
+ puts "Timed out sending command to server."
145
+
146
+ rescue EOFError
147
+ raise "The console connection has been terminated. Perhaps the app was stopped or deleted?"
148
+ end
149
+
150
+ prompt
151
+ end
152
+
153
+ def send_console_command(cmd)
154
+ results = @telnet.cmd(cmd)
155
+ results.split("\n")
156
+ end
157
+
158
+ def exit_console
159
+ @telnet.cmd("String" => "exit", "Timeout" => 1)
160
+ rescue TimeoutError
161
+ # TimeoutError expected, as exit doesn't return anything
162
+ ensure
163
+ close_console
164
+ end
165
+
166
+ def close_console
167
+ @telnet.close
168
+ end
169
+
170
+ def console_tab_completion_data(cmd)
171
+ begin
172
+ results = @telnet.
173
+ cmd("String" => cmd + "\t", "Match" => /\S*\n$/, "Timeout" => 10)
174
+ results.chomp.split(",")
175
+ rescue TimeoutError
176
+ [] #Just return empty results if timeout occurred on tab completion
177
+ end
178
+ end
179
+
180
+ def telnet_client
181
+ Net::Telnet.new(
182
+ "Port" => @port,
183
+ "Prompt" => /[$%#>] \z|Login failed/n,
184
+ "Timeout" => 30,
185
+ "FailEOF" => true)
186
+ end
187
+ end
@@ -0,0 +1,30 @@
1
+ require "cf/plugin"
2
+ require "console/console"
3
+
4
+ module CFConsolePlugin
5
+ class Console < CF::CLI
6
+ desc "Open a console connected to your app"
7
+ group :apps, :manage
8
+ input :app, :argument => :required, :from_given => by_name("app"),
9
+ :desc => "App to connect to"
10
+ input :port, :default => 10000
11
+ def console
12
+ app = input[:app]
13
+
14
+ console = CFConsole.new(client, app)
15
+ port = console.pick_port!(input[:port])
16
+
17
+ with_progress("Opening console on port #{c(port, :name)}") do
18
+ console.open!
19
+ console.wait_for_start
20
+ end
21
+
22
+ console.start_console
23
+ end
24
+
25
+ filter(:start, :start_app) do |app|
26
+ app.console = true
27
+ app
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ [![Build Status](https://travis-ci.org/cloudfoundry/manifests-cf-plugin.png)](https://travis-ci.org/cloudfoundry/manifests-cf-plugin)
2
+ [![Gem Version](https://badge.fury.io/rb/manifests-cf-plugin.png)](http://badge.fury.io/rb/manifests-cf-plugin)
3
+ [![Code Climate](https://codeclimate.com/github/cloudfoundry/manifests-cf-plugin.png)](https://codeclimate.com/github/cloudfoundry/manifests-cf-plugin)
4
+
5
+ ## Manifests
6
+ ### Info
7
+ With this plugin enabled, any configuration changes you make using the CF `start`, `restart`, `instances`, `logs`, `env`, `health`, `stats`, `scale`, and `app` commands will be saved to a file called *manifest.yml*.
8
+
9
+ ### Installation
10
+ ```
11
+ gem install manifests-cf-plugin
12
+ ```
13
+
@@ -0,0 +1,35 @@
1
+ require "cf/errors"
2
+
3
+ module CFManifests
4
+ class InvalidManifest < CF::UserFriendlyError
5
+ attr_reader :file
6
+
7
+ def initialize(file)
8
+ @file = file
9
+ end
10
+
11
+ def to_s
12
+ "Manifest file '#{@file}' is malformed."
13
+ end
14
+ end
15
+
16
+ class CircularDependency < CF::UserFriendlyError
17
+ def initialize(app)
18
+ @app = app
19
+ end
20
+
21
+ def to_s
22
+ "Circular dependency in application '#@app'"
23
+ end
24
+ end
25
+
26
+ class UnknownSymbol < CF::UserFriendlyError
27
+ def initialize(sym)
28
+ @sym = sym
29
+ end
30
+
31
+ def to_s
32
+ "Undefined symbol in manifest: '#@sym'"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ require "manifests/loader/builder"
2
+ require "manifests/loader/normalizer"
3
+ require "manifests/loader/resolver"
4
+
5
+ module CFManifests
6
+ class Loader
7
+ include Builder
8
+ include Normalizer
9
+ include Resolver
10
+
11
+ def initialize(file, resolver)
12
+ @file = file
13
+ @resolver = resolver
14
+ end
15
+
16
+ def manifest
17
+ info = build(@file)
18
+ normalize! info
19
+ resolve info, @resolver
20
+ end
21
+
22
+ private
23
+
24
+ # expand a path relative to the manifest file's directory
25
+ def from_manifest(path)
26
+ return path unless @file
27
+
28
+ File.expand_path(path, File.dirname(@file))
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ require "manifests/errors"
2
+
3
+ module CFManifests
4
+ module Builder
5
+ # parse a manifest and merge with its inherited manifests
6
+ def build(file)
7
+ manifest = YAML.load_file file
8
+ raise CFManifests::InvalidManifest.new(file) unless manifest
9
+
10
+ Array(manifest["inherit"]).each do |path|
11
+ manifest = merge_parent(path, manifest)
12
+ end
13
+
14
+ manifest.delete("inherit")
15
+
16
+ manifest
17
+ end
18
+
19
+ private
20
+
21
+ # merge the manifest at `parent_path' into the `child'
22
+ def merge_parent(parent_path, child)
23
+ merge_manifest(build(from_manifest(parent_path)), child)
24
+ end
25
+
26
+ # deep hash merge
27
+ def merge_manifest(parent, child)
28
+ merge = proc do |_, old, new|
29
+ if new.is_a?(Hash) && old.is_a?(Hash)
30
+ old.merge(new, &merge)
31
+ else
32
+ new
33
+ end
34
+ end
35
+
36
+ parent.merge(child, &merge)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,145 @@
1
+ module CFManifests
2
+ module Normalizer
3
+ MANIFEST_META = ["applications", "properties"]
4
+
5
+ def normalize!(manifest)
6
+ toplevel = toplevel_attributes(manifest)
7
+
8
+ apps = manifest["applications"]
9
+ apps ||= [{}]
10
+
11
+ default_paths_to_keys!(apps)
12
+
13
+ apps = convert_to_array(apps)
14
+
15
+ merge_toplevel!(toplevel, manifest, apps)
16
+ normalize_apps!(apps)
17
+
18
+ manifest["applications"] = apps
19
+
20
+ normalize_paths!(apps)
21
+
22
+ keyval = normalize_key_val(manifest)
23
+ manifest.clear.merge!(keyval)
24
+
25
+ nil
26
+ end
27
+
28
+ private
29
+
30
+ def normalize_paths!(apps)
31
+ apps.each do |app|
32
+ app["path"] = from_manifest(app["path"])
33
+ end
34
+ end
35
+
36
+ def convert_to_array(apps)
37
+ return apps if apps.is_a?(Array)
38
+
39
+ ordered_by_deps(apps)
40
+ end
41
+
42
+ # sort applications in dependency order
43
+ # e.g. if A depends on B, B will be listed before A
44
+ def ordered_by_deps(apps, processed = Set[])
45
+ ordered = []
46
+ apps.each do |tag, info|
47
+ next if processed.include?(tag)
48
+
49
+ if deps = Array(info["depends-on"])
50
+ dep_apps = {}
51
+ deps.each do |dep|
52
+ dep_apps[dep] = apps[dep]
53
+ end
54
+
55
+ processed.add(tag)
56
+
57
+ ordered += ordered_by_deps(dep_apps, processed)
58
+ ordered << info
59
+ else
60
+ ordered << info
61
+ processed.add(tag)
62
+ end
63
+ end
64
+
65
+ ordered.each { |app| app.delete("depends-on") }
66
+
67
+ ordered
68
+ end
69
+
70
+ def default_paths_to_keys!(apps)
71
+ return if apps.is_a?(Array)
72
+
73
+ apps.each do |tag, app|
74
+ app["path"] ||= tag
75
+ end
76
+ end
77
+
78
+ def normalize_apps!(apps)
79
+ apps.each do |app|
80
+ normalize_app!(app)
81
+ end
82
+ end
83
+
84
+ def merge_toplevel!(toplevel, manifest, apps)
85
+ return if toplevel.empty?
86
+
87
+ apps.collect! do |a|
88
+ toplevel.merge(a)
89
+ end
90
+
91
+ toplevel.each do |k, _|
92
+ manifest.delete k
93
+ end
94
+ end
95
+
96
+ def normalize_app!(app)
97
+ if app.key?("mem")
98
+ app["memory"] = app.delete("mem")
99
+ end
100
+
101
+ if app.key?("url") && app["url"].nil?
102
+ app["url"] = "none"
103
+ end
104
+
105
+ if app.key?("subdomain")
106
+ if app.key?("host")
107
+ app.delete("subdomain")
108
+ else
109
+ app["host"] = app.delete("subdomain")
110
+ end
111
+ end
112
+ end
113
+
114
+ def toplevel_attributes(manifest)
115
+ top =
116
+ manifest.reject { |k, _|
117
+ MANIFEST_META.include? k
118
+ }
119
+
120
+ # implicit toplevel path of .
121
+ top["path"] ||= "."
122
+
123
+ top
124
+ end
125
+
126
+ def normalize_key_val(val)
127
+ case val
128
+ when Hash
129
+ stringified = {}
130
+
131
+ val.each do |k, v|
132
+ stringified[k.to_sym] = normalize_key_val(v)
133
+ end
134
+
135
+ stringified
136
+ when Array
137
+ val.collect { |x| normalize_key_val(x) }
138
+ when nil
139
+ nil
140
+ else
141
+ val.to_s
142
+ end
143
+ end
144
+ end
145
+ end