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
@@ -29,7 +29,7 @@ module CF
29
29
 
30
30
  let(:apps) { Array.new(2) { build(:app) } }
31
31
  let(:domains) { Array.new(2) { build(:domain) } }
32
- let(:services) { Array.new(2) { build(:service_instance) } }
32
+ let(:services) { Array.new(2) { build(:managed_service_instance) } }
33
33
  let(:space) { build(:space, :name => "some_space_name", :apps => apps, :service_instances => services, :domains => domains, :organization => organization ) }
34
34
  let(:spaces) { [space] }
35
35
  let(:organization) { build(:organization, :name => "Spacey Org") }
@@ -5,9 +5,9 @@ module CF
5
5
  describe Spaces do
6
6
  let(:full) { false }
7
7
  let(:app) { build(:app) }
8
- let!(:space_1) { build(:space, :name => "bb_second", :apps => [app], :service_instances => [build(:service_instance)]) }
9
- let!(:space_2) { build(:space, :name => "aa_first", :apps => [app], :service_instances => [build(:service_instance)], :domains => [build(:domain)]) }
10
- let!(:space_3) { build(:space, :name => "cc_last", :apps => [app], :service_instances => [build(:service_instance)], :domains => [build(:domain)]) }
8
+ let!(:space_1) { build(:space, :name => "bb_second", :apps => [app], :service_instances => [build(:managed_service_instance)]) }
9
+ let!(:space_2) { build(:space, :name => "aa_first", :apps => [app], :service_instances => [build(:managed_service_instance)], :domains => [build(:domain)]) }
10
+ let!(:space_3) { build(:space, :name => "cc_last", :apps => [app], :service_instances => [build(:managed_service_instance)], :domains => [build(:domain)]) }
11
11
  let(:spaces) { [space_1, space_2, space_3] }
12
12
  let(:organization) { build(:organization, :spaces => spaces, :name => "foo") }
13
13
  let(:client) do
@@ -1,5 +1,5 @@
1
1
  FactoryGirl.define do
2
- factory :service_instance, :class => CFoundry::V2::ServiceInstance do
2
+ factory :managed_service_instance, :class => CFoundry::V2::ManagedServiceInstance do
3
3
  sequence(:guid) { |n| "service-instance-guid-#{n}" }
4
4
  sequence(:name) { |n| "service-instance-name-#{n}" }
5
5
 
@@ -9,4 +9,4 @@ FactoryGirl.define do
9
9
 
10
10
  initialize_with { new(guid, client) }
11
11
  end
12
- end
12
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+ factory :user_provided_service_instance, :class => CFoundry::V2::UserProvidedServiceInstance do
3
+ sequence(:guid) { |n| "user-provided-service-instance-guid-#{n}" }
4
+ sequence(:name) { |n| "user-provided-service-instance-name-#{n}" }
5
+
6
+ ignore do
7
+ client { FactoryGirl.build(:client) }
8
+ end
9
+
10
+ initialize_with { new(guid, client) }
11
+ end
12
+ end
@@ -0,0 +1,64 @@
1
+ require "spec_helper"
2
+ require "webmock/rspec"
3
+
4
+ if ENV["CF_V2_RUN_INTEGRATION"]
5
+ describe "A user deleting an app bound to a user-provided service" do
6
+ let(:run_id) { TRAVIS_BUILD_ID.to_s + Time.new.to_f.to_s.gsub(".", "_") }
7
+ let(:app) { "hello-sinatra-#{run_id}" }
8
+ let(:user_provided_name) { "user-provided-#{run_id}"}
9
+
10
+ before do
11
+ FileUtils.rm_rf File.expand_path(CF::CONFIG_DIR)
12
+ WebMock.allow_net_connect!
13
+ login
14
+ end
15
+
16
+ after do
17
+ `#{cf_bin} unbind-service -f --no-script #{user_provided_name} #{app}`
18
+ `#{cf_bin} delete-service -f --no-script #{user_provided_name}`
19
+
20
+ `#{cf_bin} delete #{app} -f --routes --no-script`
21
+ logout
22
+ end
23
+
24
+ it "can delete the user-provided service when given --delete-orphaned" do
25
+ Dir.chdir("#{SPEC_ROOT}/assets/hello-sinatra") do
26
+ FileUtils.rm("manifest.yml", force: true)
27
+ File.open("manifest.yml", "w") do |f|
28
+ f.write(<<-MANIFEST)
29
+ ---
30
+ applications:
31
+ - name: #{app}
32
+ memory: 256M
33
+ instances: 1
34
+ host: ~
35
+ domain: none
36
+ path: .
37
+ services:
38
+ #{user_provided_name}:
39
+ label: user-provided
40
+ credentials:
41
+ username: abc123
42
+ MANIFEST
43
+ end
44
+
45
+ BlueShell::Runner.run("#{cf_bin} push --no-start") do |runner|
46
+ expect(runner).to say "Using manifest file manifest.yml"
47
+ expect(runner).to say "Creating #{app}... OK"
48
+
49
+ expect(runner).to say /Creating service #{user_provided_name}.*OK/
50
+ expect(runner).to say /Binding #{user_provided_name} to #{app}... OK/
51
+
52
+ expect(runner).to say "Uploading #{app}... OK"
53
+ end
54
+ end
55
+
56
+ BlueShell::Runner.run("#{cf_bin} delete #{app} --delete-orphaned --force") do |runner|
57
+ expect(runner).to say "Deleting #{app}... OK"
58
+ expect(runner).to say "Deleting #{user_provided_name}... OK"
59
+ end
60
+ end
61
+ end
62
+ else
63
+ $stderr.puts 'Skipping v2 integration specs; please provide necessary environment variables'
64
+ end
@@ -0,0 +1,86 @@
1
+ require "spec_helper"
2
+ require "webmock/rspec"
3
+
4
+ if ENV["CF_V2_RUN_INTEGRATION"]
5
+ describe "A user pushing a new sinatra app" do
6
+
7
+ let(:run_id) { TRAVIS_BUILD_ID.to_s + Time.new.to_f.to_s.gsub(".", "_") }
8
+ let(:app) { "hello-sinatra-#{run_id}" }
9
+ let(:subdomain) { "hello-sinatra-subdomain-#{run_id}" }
10
+ let(:user_provided_name) { "user-provided-#{run_id}"}
11
+
12
+ before do
13
+ FileUtils.rm_rf File.expand_path(CF::CONFIG_DIR)
14
+ WebMock.allow_net_connect!
15
+ login
16
+ end
17
+
18
+ after do
19
+ `#{cf_bin} unbind-service -f --no-script #{user_provided_name} #{app}`
20
+ `#{cf_bin} delete-service -f --no-script #{user_provided_name}`
21
+
22
+ `#{cf_bin} delete #{app} -f --routes --no-script`
23
+ logout
24
+ end
25
+
26
+ context "with user-provided service" do
27
+ it "reads the manifest when pushing" do
28
+ Dir.chdir("#{SPEC_ROOT}/assets/hello-sinatra") do
29
+ FileUtils.rm("manifest.yml", force: true)
30
+ File.open("manifest.yml", "w") do |f|
31
+ f.write(<<-MANIFEST)
32
+ ---
33
+ applications:
34
+ - name: #{app}
35
+ memory: 256M
36
+ instances: 1
37
+ host: #{subdomain}
38
+ domain: a1-app.cf-app.com
39
+ path: .
40
+ services:
41
+ #{user_provided_name}:
42
+ label: user-provided
43
+ credentials:
44
+ username: abc123
45
+ password: sunshine
46
+ hostname: oracle.enterprise.com
47
+ port: 1234
48
+ name: myoracledb2
49
+ MANIFEST
50
+ end
51
+
52
+ BlueShell::Runner.run("#{cf_bin} push") do |runner|
53
+ expect(runner).to say "Using manifest file manifest.yml"
54
+ expect(runner).to say "Creating #{app}... OK"
55
+
56
+ expect(runner).to say(/Creating route #{subdomain}\..*\.\.\. OK/)
57
+ expect(runner).to say(/Binding #{subdomain}\..* to #{app}\.\.\. OK/)
58
+
59
+ expect(runner).to say /Creating service #{user_provided_name}.*OK/
60
+ expect(runner).to say /Binding #{user_provided_name} to #{app}... OK/
61
+
62
+ expect(runner).to say "Uploading #{app}... OK", 180
63
+ expect(runner).to say "Preparing to start #{app}... OK", 180
64
+ expect(runner).to say "Checking status of app '#{app}'...", 180
65
+ expect(runner).to say "1 of 1 instances running"
66
+ expect(runner).to say "Push successful! App '#{app}' available at http://#{subdomain}.a1-app.cf-app.com", 30
67
+ end
68
+ end
69
+
70
+ BlueShell::Runner.run("#{cf_bin} services") do |runner|
71
+ expect(runner).to say /name\s+service\s+provider\s+version\s+plan\s+bound apps/
72
+ expect(runner).to say /#{user_provided_name}\s+ # name
73
+ user-provided\s+ # service
74
+ n\/a\s+ # provider
75
+ n\/a\s+ # version
76
+ n\/a\s+ # plan
77
+ #{app} # bound apps
78
+ /x
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ else
85
+ $stderr.puts 'Skipping v2 integration specs; please provide necessary environment variables'
86
+ end
@@ -24,13 +24,13 @@ if ENV["CF_V2_RUN_INTEGRATION"]
24
24
  end
25
25
 
26
26
  it "can create and recursively delete an org" do
27
- BlueShell::Runner.run("cf create-org #{new_org_name}") do |runner|
27
+ BlueShell::Runner.run("#{cf_bin} create-org #{new_org_name}") do |runner|
28
28
  runner.should say "Creating organization #{new_org_name}... OK"
29
29
  runner.should say "Switching to organization #{new_org_name}... OK"
30
30
  runner.should say "There are no spaces. You may want to create one with create-space."
31
31
  end
32
32
 
33
- BlueShell::Runner.run("cf create-space new-space") do |runner|
33
+ BlueShell::Runner.run("#{cf_bin} create-space new-space") do |runner|
34
34
  runner.should say "Creating space new-space... OK"
35
35
  end
36
36
 
@@ -39,11 +39,11 @@ if ENV["CF_V2_RUN_INTEGRATION"]
39
39
  # runner.should say "If you want to delete the organization along with all dependent objects, rerun the command with the '--recursive' flag."
40
40
  #end
41
41
 
42
- BlueShell::Runner.run("cf delete-org #{new_org_name} --force --recursive") do |runner|
42
+ BlueShell::Runner.run("#{cf_bin} delete-org #{new_org_name} --force --recursive") do |runner|
43
43
  runner.should say("Deleting organization #{new_org_name}... OK")
44
44
  end
45
45
 
46
- BlueShell::Runner.run("cf orgs") do |runner|
46
+ BlueShell::Runner.run("#{cf_bin} orgs") do |runner|
47
47
  runner.should_not say("#{new_org_name}")
48
48
  end
49
49
  end
@@ -3,12 +3,11 @@ require "webmock/rspec"
3
3
 
4
4
  if ENV["CF_V2_RUN_INTEGRATION"]
5
5
  describe "A user pushing a new sinatra app", :ruby19 => true do
6
- include CF::Interactive
7
-
8
6
  let(:run_id) { TRAVIS_BUILD_ID.to_s + Time.new.to_f.to_s.gsub(".", "_") }
9
7
  let(:app) { "hello-sinatra-#{run_id}" }
10
8
  let(:subdomain) { "hello-sinatra-subdomain-#{run_id}" }
11
9
  let(:service_name) { "dummy-service-#{run_id}" }
10
+ let(:user_provided_name) { "user-provided-#{run_id}"}
12
11
 
13
12
  before do
14
13
  FileUtils.rm_rf File.expand_path(CF::CONFIG_DIR)
@@ -20,6 +19,10 @@ if ENV["CF_V2_RUN_INTEGRATION"]
20
19
  after do
21
20
  `#{cf_bin} unbind-service -f --no-script #{service_name} #{app}`
22
21
  `#{cf_bin} delete-service -f --no-script #{service_name}`
22
+
23
+ `#{cf_bin} unbind-service -f --no-script #{user_provided_name} #{app}`
24
+ `#{cf_bin} delete-service -f --no-script #{user_provided_name}`
25
+
23
26
  `#{cf_bin} delete #{app} -f --routes --no-script`
24
27
  logout
25
28
  Interact::Progress::Dots.stop!
@@ -31,6 +34,7 @@ if ENV["CF_V2_RUN_INTEGRATION"]
31
34
  end
32
35
 
33
36
  Dir.chdir("#{SPEC_ROOT}/assets/hello-sinatra") do
37
+ FileUtils.rm("manifest.yml", force: true)
34
38
  BlueShell::Runner.run("#{cf_bin} push") do |runner|
35
39
  expect(runner).to say "Name>"
36
40
  runner.send_keys app
@@ -85,7 +89,27 @@ if ENV["CF_V2_RUN_INTEGRATION"]
85
89
  expect(runner).not_to say "Which plan?>"
86
90
  runner.send_up_arrow
87
91
  expect(runner).not_to say "Which plan?>"
88
- runner.send_return
92
+ runner.send_keys "y"
93
+
94
+ # create a user-provided service here
95
+ expect(runner).to say "What kind?>"
96
+ runner.send_keys "user-provided"
97
+
98
+ expect(runner).to say "Name?>"
99
+ runner.send_keys user_provided_name
100
+
101
+ expect(runner).not_to say "Which plan?>"
102
+ expect(runner).to say "What credential parameters should applications use to connect to this service instance?\n(e.g. hostname, port, password)>"
103
+ runner.send_keys "uri"
104
+
105
+ expect(runner).to say "uri>"
106
+ runner.send_keys "mysql://u:p@example.com:port/db"
107
+
108
+ expect(runner).to say /Creating service #{user_provided_name}.*OK/
109
+ expect(runner).to say /Binding .+ to .+ OK/
110
+
111
+ expect(runner).to say "Create another service?> n"
112
+ runner.send_keys "n"
89
113
 
90
114
  if runner.expect "Bind other services to application?> n", 15
91
115
  runner.send_return
@@ -6,6 +6,25 @@ if ENV['CF_V2_RUN_INTEGRATION']
6
6
  login
7
7
  end
8
8
 
9
+ describe "listing services" do
10
+ let(:service1) { "some-provided-instance-#{Time.now.to_i}" }
11
+ let(:service2) { "cf-managed-instance-#{Time.now.to_i}" }
12
+
13
+ it "shows all service instances in the space" do
14
+ create_service_instance("user-provided", service1, credentials: { hostname: "myservice.com"} )
15
+ create_service_instance("dummy-dev", service2, plan: "small")
16
+
17
+ BlueShell::Runner.run("#{cf_bin} services") do |runner|
18
+ expect(runner).to say /#{service1}\s+user-provided\s+n\/a\s+n\/a\s+n\/a\s+.*/
19
+ end
20
+ end
21
+
22
+ after do
23
+ delete_service(service1)
24
+ delete_service(service2)
25
+ end
26
+ end
27
+
9
28
  describe "creating a service" do
10
29
  describe "when the user leaves the line blank for a plan" do
11
30
  it "re-prompts for the plan" do
@@ -20,6 +39,83 @@ if ENV['CF_V2_RUN_INTEGRATION']
20
39
  end
21
40
  end
22
41
  end
42
+
43
+ describe "when the service is a user-provided instance" do
44
+ let(:service_name) { "my-private-db-#{Random.rand(1000) + 1000}"}
45
+
46
+ it "can create a service instance" do
47
+ BlueShell::Runner.run("#{cf_bin} create-service") do |runner|
48
+ expect(runner).to say "What kind?"
49
+ runner.send_keys "user-provided"
50
+
51
+ expect(runner).to say "Name?"
52
+ runner.send_keys service_name
53
+
54
+ expect(runner).to say "What credential parameters should applications use to connect to this service instance?\n(e.g. hostname, port, password)"
55
+ runner.send_keys "hostname"
56
+ expect(runner).to say "hostname"
57
+ runner.send_keys "myserviceinstance.com"
58
+
59
+ expect(runner).to say /Creating service #{service_name}.+ OK/
60
+ end
61
+ end
62
+
63
+ after do
64
+ delete_service(service_name)
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "binding to a service" do
70
+ let(:app_folder) { "env" }
71
+ let(:app_name) { "services_env_test_app-#{Time.now.to_i}" }
72
+
73
+ let(:service_name) { "some-provided-instance-#{Time.now.to_i}" }
74
+
75
+ it "can bind and unbind user-provided services to apps" do
76
+ push_app(app_folder, app_name, start_command: "'bundle exec ruby env_test.rb -p $PORT'", timeout: 90)
77
+ create_service_instance("user-provided", service_name, credentials: { hostname: "myservice.com"} )
78
+
79
+ BlueShell::Runner.run("#{cf_bin} bind-service") do |runner|
80
+ expect(runner).to say "Which application?>"
81
+ runner.send_keys app_name
82
+
83
+ expect(runner).to say "Which service?>"
84
+ runner.send_keys service_name
85
+
86
+ expect(runner).to say "Binding #{service_name} to #{app_name}... OK"
87
+ end
88
+
89
+ BlueShell::Runner.run("#{cf_bin} unbind-service") do |runner|
90
+ expect(runner).to say "Which application?"
91
+ runner.send_keys app_name
92
+
93
+ expect(runner).to say "Which service?>"
94
+ runner.send_keys service_name
95
+
96
+ expect(runner).to say "Unbinding #{service_name} from #{app_name}... OK"
97
+ end
98
+ end
99
+
100
+ after do
101
+ delete_app(app_name)
102
+ end
103
+ end
104
+
105
+ def delete_service(service_name)
106
+ BlueShell::Runner.run("#{cf_bin} delete-service --service #{service_name} --force") do |runner|
107
+ expect(runner).to say "Deleting #{service_name}... OK"
108
+ end
109
+ end
110
+
111
+ def delete_app(app_name, routes=true)
112
+ delete_cmd = "#{cf_bin} delete #{app_name}"
113
+ delete_cmd + " --routes" if routes
114
+ BlueShell::Runner.run(delete_cmd) do |runner|
115
+ expect(runner).to say "Really delete #{app_name}?"
116
+ runner.send_keys "y"
117
+ expect(runner).to say "Deleting #{app_name}... OK"
118
+ end
23
119
  end
24
120
  end
25
121
  end
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe "Service Broker Management", components: [:nats, :uaa, :ccng] do
4
+ let(:username) { 'admin' }
5
+ let(:password) { 'the_admin_pw' }
6
+ let(:target) { 'http://127.0.0.1:8181' }
7
+
8
+ before do
9
+ create_user_in_ccng
10
+ logout
11
+ end
12
+
13
+ after do
14
+ logout
15
+ end
16
+
17
+ it "allows an admin user to add a service broker" do
18
+ BlueShell::Runner.run("#{cf_bin} target #{target}") do |runner|
19
+ runner.wait_for_exit
20
+
21
+ expect(runner).to be_successful
22
+ end
23
+
24
+ BlueShell::Runner.run("#{cf_bin} login #{username} --password #{password}") do |runner|
25
+ expect(runner).to say "Authenticating... OK"
26
+ end
27
+
28
+ BlueShell::Runner.run("#{cf_bin} add-service-broker --name cf-mysql --url http://cf-mysql.cfapp.io --token cfmysqlsecret") do |runner|
29
+ expect(runner).to say "... OK"
30
+ end
31
+ end
32
+
33
+ def create_user_in_ccng
34
+ ccng_post "/v2/users", {
35
+ guid: user_guid
36
+ }
37
+ end
38
+
39
+ def user_guid
40
+ uaa_port = component!(:uaa).port
41
+ token_issuer = CF::UAA::TokenIssuer.new("http://localhost:#{uaa_port}", 'cf')
42
+ auth_header = token_issuer.owner_password_grant(username, password).auth_header
43
+ response = Typhoeus::Request.new(
44
+ "http://localhost:#{uaa_port}/Users?filter=userName+eq+'#{username}'",
45
+ headers: {'Authorization' => auth_header}
46
+ ).run
47
+ JSON.parse(response.body).fetch("resources").first.fetch('id')
48
+ end
49
+ end