cf 5.0.0.rc1 → 5.0.0.rc3

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 (36) hide show
  1. data/lib/admin/plugin.rb +1 -0
  2. data/lib/admin/service_broker/add.rb +46 -0
  3. data/lib/cf/cli.rb +8 -3
  4. data/lib/cf/cli/service/create.rb +68 -20
  5. data/lib/cf/cli/service/delete.rb +1 -1
  6. data/lib/cf/cli/service/service_instance_helper.rb +99 -0
  7. data/lib/cf/cli/service/services.rb +12 -32
  8. data/lib/cf/cli/start/target.rb +1 -1
  9. data/lib/cf/version.rb +1 -1
  10. data/lib/manifests/manifests.rb +41 -25
  11. data/lib/tasks/gem_release.rake +1 -1
  12. data/spec/admin/service_broker/add_spec.rb +59 -0
  13. data/spec/assets/env/Gemfile +4 -0
  14. data/spec/assets/env/Gemfile.lock +20 -0
  15. data/spec/assets/env/env_test.rb +58 -0
  16. data/spec/cf/cli/app/delete_spec.rb +2 -2
  17. data/spec/cf/cli/app/push/create_spec.rb +1 -1
  18. data/spec/cf/cli/service/create_spec.rb +51 -4
  19. data/spec/cf/cli/service/rename_spec.rb +1 -1
  20. data/spec/cf/cli/service/service_instance_helper_spec.rb +155 -0
  21. data/spec/cf/cli/service/services_spec.rb +63 -34
  22. data/spec/cf/cli/space/space_spec.rb +1 -1
  23. data/spec/cf/cli/space/spaces_spec.rb +3 -3
  24. data/spec/factories/cfoundry/v2/{service_instances_factory.rb → managed_service_instances_factory.rb} +2 -2
  25. data/spec/factories/cfoundry/v2/user_provided_service_instances_factory.rb +12 -0
  26. data/spec/features/delete_orphaned_service_spec.rb +64 -0
  27. data/spec/features/manifests_spec.rb +86 -0
  28. data/spec/features/org_spec.rb +4 -4
  29. data/spec/{integration → features}/push_flow_spec.rb +27 -3
  30. data/spec/features/services_spec.rb +96 -0
  31. data/spec/integration/service_broker_spec.rb +49 -0
  32. data/spec/manifests/manifests_spec.rb +46 -25
  33. data/spec/spec_helper.rb +7 -1
  34. data/spec/support/features_helper.rb +36 -3
  35. data/spec/support/matchers.rb +14 -3
  36. metadata +109 -9
data/lib/admin/plugin.rb CHANGED
@@ -2,3 +2,4 @@ require "admin/curl"
2
2
  require "admin/guid"
3
3
  require "admin/set_quota"
4
4
  require "admin/service_auth_token"
5
+ require "admin/service_broker/add"
@@ -0,0 +1,46 @@
1
+ require "cf/cli"
2
+
3
+ module CFAdmin::ServiceBroker
4
+ class Add < CF::CLI
5
+ def precondition
6
+ check_target
7
+ end
8
+
9
+ desc "Add a Service Broker."
10
+ group :admin
11
+ input :name, :argument => :optional,
12
+ :desc => "broker name"
13
+ input :url,
14
+ :desc => "broker url"
15
+ input :token,
16
+ :desc => "broker token"
17
+
18
+ def add_service_broker
19
+ broker = client.service_broker
20
+
21
+ broker.name = input[:name]
22
+ finalize
23
+ broker.broker_url = input[:url]
24
+ finalize
25
+ broker.token = input[:token]
26
+ finalize
27
+
28
+ with_progress("") do
29
+ broker.create!
30
+ end
31
+ end
32
+
33
+ private
34
+ def ask_name
35
+ ask("name")
36
+ end
37
+
38
+ def ask_url
39
+ ask("url")
40
+ end
41
+
42
+ def ask_token
43
+ ask("token")
44
+ end
45
+ end
46
+ end
data/lib/cf/cli.rb CHANGED
@@ -414,10 +414,8 @@ EOS
414
414
 
415
415
  fail "V1 targets are no longer supported." if info[:version] == 1
416
416
 
417
- @@client = CFoundry::V2::Client.new(target, token)
417
+ @@client = build_client(target, token)
418
418
 
419
- @@client.http_proxy = input[:http_proxy] || ENV['HTTP_PROXY'] || ENV['http_proxy']
420
- @@client.https_proxy = input[:https_proxy] || ENV['HTTPS_PROXY'] || ENV['https_proxy']
421
419
  @@client.trace = input[:trace]
422
420
 
423
421
  uri = URI.parse(target)
@@ -435,6 +433,13 @@ EOS
435
433
  rescue CFoundry::InvalidTarget
436
434
  end
437
435
 
436
+ def build_client(target, token = nil)
437
+ client = CFoundry::V2::Client.new(target, token)
438
+ client.http_proxy = input[:http_proxy] || ENV['HTTP_PROXY'] || ENV['http_proxy']
439
+ client.https_proxy = input[:https_proxy] || ENV['HTTPS_PROXY'] || ENV['https_proxy']
440
+ client
441
+ end
442
+
438
443
  def fail_unknown(display, name)
439
444
  fail("Unknown #{display} '#{name}'.")
440
445
  end
@@ -1,6 +1,16 @@
1
1
  require "cf/cli/service/base"
2
2
 
3
3
  module CF::Service
4
+ USER_PROVIDED_OFFERING = "user-provided" # I'd rather move this to CFoundry
5
+
6
+ class UPDummy
7
+ def label
8
+ "user-provided"
9
+ end
10
+
11
+ attr_reader :version, :provider
12
+ end
13
+
4
14
  class Create < Base
5
15
  offerings_from_label = proc { |label, offerings|
6
16
  offerings.select { |s| s.label == label }
@@ -46,6 +56,8 @@ module CF::Service
46
56
  end
47
57
  finalize
48
58
 
59
+ offerings << UPDummy.new
60
+
49
61
  selected_offerings = offerings.any? ? Array(input[:offering, offerings.sort_by(&:label)]) : []
50
62
  finalize
51
63
 
@@ -55,48 +67,84 @@ module CF::Service
55
67
 
56
68
  offering = selected_offerings.first
57
69
 
58
- service = client.service_instance
59
- service.name = input[:name, offering]
60
- finalize
61
- plan = input[:plan, offering.service_plans]
62
- finalize
63
- service.service_plan = if plan.is_a?(String)
64
- offering.service_plans.find { |p| p.name.casecmp(plan) == 0 }
65
- else
66
- plan
67
- end
68
- service.space = client.current_space
69
-
70
- with_progress("Creating service #{c(service.name, :name)}") do
71
- service.create!
70
+ if offering.label == CF::Service::USER_PROVIDED_OFFERING
71
+ service_instance = client.user_provided_service_instance
72
+ service_instance.name = input[:name, offering]
73
+ finalize
74
+
75
+ # at this point there's no way input[:credentials] can work interactively...
76
+ service_instance.credentials = input[:credentials, nil] || ask_credentials
77
+ else
78
+ service_instance = client.managed_service_instance
79
+ service_instance.name = input[:name, offering]
80
+ finalize
81
+
82
+ plan = input[:plan, offering.service_plans]
83
+ finalize
84
+ service_instance.service_plan = if plan.is_a?(String)
85
+ offering.service_plans.find { |p| p.name.casecmp(plan) == 0 }
86
+ else
87
+ plan
88
+ end
89
+ end
90
+
91
+ service_instance.space = client.current_space
92
+
93
+ with_progress("Creating service #{c(service_instance.name, :name)}") do
94
+ service_instance.create!
72
95
  end
73
96
 
74
97
  app = input[:app]
75
98
  finalize
76
99
 
77
100
  if app
78
- invoke :bind_service, :service => service, :app => app
101
+ invoke :bind_service, :service => service_instance, :app => app
79
102
  end
80
- service
103
+ service_instance
81
104
  end
82
105
 
83
106
  private
84
107
 
108
+ def ask_credentials
109
+ credentials = {}
110
+
111
+ while keys = ask("What credential parameters should applications use to connect to this service instance?\n(e.g. hostname, port, password)").split(/\s*,\s*/).map(&:strip)
112
+ if bad_key = keys.detect { |key| key !~ /^[-\w]+$/ }
113
+ line("'#{bad_key}' is not a valid key")
114
+ else
115
+ break
116
+ end
117
+ end
118
+ finalize
119
+ keys.each do |key|
120
+ value = ask(key)
121
+ finalize
122
+ credentials[key] = value
123
+ end
124
+
125
+ credentials
126
+ end
127
+
85
128
  def ask_offering(offerings)
86
129
  [ask("What kind?", :choices => offerings.sort_by(&:label),
87
- :display => proc { |s|
130
+ :display => proc do |s|
88
131
  str = "#{c(s.label, :name)} #{s.version}"
89
132
  if s.provider != "core"
90
133
  str << ", via #{s.provider}"
91
134
  end
92
135
  str
93
- },
136
+ end,
94
137
  :complete => proc { |s| "#{s.label} #{s.version}" })]
95
138
  end
96
139
 
97
140
  def ask_name(offering)
98
- random = sprintf("%x", rand(1000000))
99
- ask "Name?", :default => "#{offering.label}-#{random}"
141
+ default = nil
142
+ unless offering == CF::Service::USER_PROVIDED_OFFERING
143
+ random = sprintf("%x", rand(1000000))
144
+ default = "#{offering.label}-#{random}"
145
+ end
146
+
147
+ ask "Name?", :default => default
100
148
  end
101
149
 
102
150
  def ask_plan(plans)
@@ -4,7 +4,7 @@ module CF::Service
4
4
  class Delete < Base
5
5
  desc "Delete a service"
6
6
  group :services, :manage
7
- input :service, :desc => "Service to bind", :argument => :optional,
7
+ input :service, :desc => "Service to delete", :argument => :optional,
8
8
  :from_given => by_name(:service_instance, :service)
9
9
  input :unbind, :desc => "Unbind from applications before deleting?",
10
10
  :type => :boolean, :default => proc { force? || interact }
@@ -0,0 +1,99 @@
1
+ class ServiceInstanceHelper
2
+ def self.new(instance)
3
+ "#{instance.class.name.demodulize}Helper".constantize.new(instance)
4
+ end
5
+ end
6
+
7
+ class UserProvidedServiceInstanceHelper
8
+ def initialize(instance)
9
+ @instance = instance
10
+ end
11
+
12
+ def service_label
13
+ "user-provided"
14
+ end
15
+
16
+ def service_provider
17
+ "n/a"
18
+ end
19
+
20
+ def version
21
+ "n/a"
22
+ end
23
+
24
+ def plan_name
25
+ "n/a"
26
+ end
27
+
28
+ def matches(opts = {})
29
+ label = opts[:service]
30
+ if label
31
+ return label == service_label
32
+ end
33
+
34
+ true
35
+ end
36
+
37
+ def name
38
+ @instance.name
39
+ end
40
+
41
+ def service_bindings
42
+ @instance.service_bindings
43
+ end
44
+ end
45
+
46
+ class ManagedServiceInstanceHelper
47
+ def initialize(service_instance)
48
+ @instance = service_instance
49
+ end
50
+
51
+ def service_label
52
+ @instance.service_plan.service.label
53
+ end
54
+
55
+ def service_provider
56
+ @instance.service_plan.service.provider
57
+ end
58
+
59
+ def version
60
+ @instance.service_plan.service.version
61
+ end
62
+
63
+ def plan_name
64
+ @instance.service_plan.name
65
+ end
66
+
67
+ def service_bindings
68
+ @instance.service_bindings
69
+ end
70
+
71
+ def name
72
+ @instance.name
73
+ end
74
+
75
+ def matches(opts = {})
76
+ service = opts[:service]
77
+ plan = opts[:plan]
78
+ provider = opts[:provider]
79
+ version = opts[:version]
80
+
81
+ if service
82
+ return false unless File.fnmatch(service, service_label)
83
+ end
84
+
85
+ if plan
86
+ return false unless File.fnmatch(plan.upcase, plan_name.upcase)
87
+ end
88
+
89
+ if provider
90
+ return false unless File.fnmatch(provider, service_provider)
91
+ end
92
+
93
+ if version
94
+ return false unless File.fnmatch(version, self.version)
95
+ end
96
+
97
+ true
98
+ end
99
+ end
@@ -71,19 +71,16 @@ module CF::Service
71
71
  def show_services_table
72
72
  table(
73
73
  ["name", "service", "provider", "version", "plan", "bound apps"],
74
- @services.collect { |i|
75
- apps = name_list(i.service_bindings.collect(&:app))
76
- plan = i.service_plan
77
-
78
- unless plan
79
- [ c(i.name, :name), "none", "none", "none", "none", apps]
80
- else
81
- service = plan.service
82
- label = service.label
83
- version = service.version
84
- provider = service.provider
85
- [ c(i.name, :name), label, provider, version, plan.name, apps]
86
- end
74
+ @services.collect { |instance|
75
+ presenter = ServiceInstanceHelper.new(instance)
76
+ apps = name_list(presenter.service_bindings.collect(&:app))
77
+
78
+ label = presenter.service_label
79
+ provider = presenter.service_provider
80
+ version = presenter.version
81
+ plan_name = presenter.plan_name
82
+
83
+ [ c(presenter.name, :name), label, provider, version, plan_name, apps]
87
84
  })
88
85
 
89
86
  end
@@ -105,25 +102,8 @@ module CF::Service
105
102
  return false unless File.fnmatch(name, i.name)
106
103
  end
107
104
 
108
- plan = i.service_plan
109
-
110
- if service = options[:service]
111
- return false unless File.fnmatch(service, plan.service.label)
112
- end
113
-
114
- if plan = options[:plan]
115
- return false unless File.fnmatch(plan.upcase, plan.name.upcase)
116
- end
117
-
118
- if provider = options[:provider]
119
- return false unless File.fnmatch(provider, plan.service.provider)
120
- end
121
-
122
- if version = options[:version]
123
- return false unless File.fnmatch(version, plan.service.version)
124
- end
125
-
126
- true
105
+ helper = ServiceInstanceHelper.new(i)
106
+ return helper.matches(options)
127
107
  end
128
108
  end
129
109
  end
@@ -21,7 +21,7 @@ module CF::Start
21
21
  target = sane_target_url(input[:url])
22
22
  with_progress("Setting target to #{c(target, :name)}") do
23
23
  begin
24
- CFoundry::Client.get(target) # check that it's valid before setting
24
+ build_client(target).info # check that it's valid before setting
25
25
  rescue CFoundry::TargetRefused
26
26
  fail "Target refused connection."
27
27
  rescue CFoundry::InvalidTarget
data/lib/cf/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CF
2
- VERSION = "5.0.0.rc1".freeze
2
+ VERSION = "5.0.0.rc3".freeze
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require "yaml"
2
2
  require "set"
3
+ require "cf/cli/service/create"
3
4
 
4
5
  require "manifests/loader"
5
6
 
@@ -182,16 +183,23 @@ module CFManifests
182
183
  unless services.empty?
183
184
  meta["services"] = {}
184
185
 
185
- services.each do |i|
186
- p = i.service_plan
187
- s = p.service
188
-
189
- meta["services"][i.name] = {
190
- "label" => s.label,
191
- "provider" => s.provider,
192
- "version" => s.version,
193
- "plan" => p.name
194
- }
186
+ services.each do |service_instance|
187
+ if service_instance.is_a?(CFoundry::V2::UserProvidedServiceInstance)
188
+ meta["services"][service_instance.name] = {
189
+ "label" => "user-provided",
190
+ "credentials" => service_instance.credentials.stringify_keys,
191
+ }
192
+ else
193
+ service_plan = service_instance.service_plan
194
+ service = service_plan.service
195
+
196
+ meta["services"][service_instance.name] = {
197
+ "label" => service.label,
198
+ "provider" => service.provider,
199
+ "version" => service.version,
200
+ "plan" => service_plan.name
201
+ }
202
+ end
195
203
  end
196
204
  end
197
205
 
@@ -292,25 +300,33 @@ module CFManifests
292
300
  if instance = client.service_instance_by_name(name)
293
301
  to_bind << instance
294
302
  else
295
- offering = offerings.find { |o|
296
- o.label == (svc[:label] || svc[:type] || svc[:vendor]) &&
297
- (!svc[:version] || o.version == svc[:version]) &&
298
- (o.provider == (svc[:provider] || "core"))
299
- }
303
+ if svc[:label] == "user-provided"
304
+ invoke :create_service,
305
+ name: name,
306
+ offering: CF::Service::UPDummy.new,
307
+ app: app,
308
+ credentials: svc[:credentials]
309
+ else
310
+ offering = offerings.find { |o|
311
+ o.label == (svc[:label] || svc[:type] || svc[:vendor]) &&
312
+ (!svc[:version] || o.version == svc[:version]) &&
313
+ (o.provider == (svc[:provider] || "core"))
314
+ }
300
315
 
301
- fail "Unknown service offering: #{svc.inspect}." unless offering
316
+ fail "Unknown service offering: #{svc.inspect}." unless offering
302
317
 
303
- plan = offering.service_plans.find { |p|
304
- p.name == (svc[:plan] || "D100")
305
- }
318
+ plan = offering.service_plans.find { |p|
319
+ p.name == (svc[:plan] || "D100")
320
+ }
306
321
 
307
- fail "Unknown service plan: #{svc[:plan]}." unless plan
322
+ fail "Unknown service plan: #{svc[:plan]}." unless plan
308
323
 
309
- invoke :create_service,
310
- :name => name,
311
- :offering => offering,
312
- :plan => plan,
313
- :app => app
324
+ invoke :create_service,
325
+ :name => name,
326
+ :offering => offering,
327
+ :plan => plan,
328
+ :app => app
329
+ end
314
330
  end
315
331
  end
316
332