bosh-bootstrap 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,6 +42,19 @@ class Bosh::Providers::AWS < Bosh::Providers::BaseProvider
42
42
  aws_compute_flavors.map { |fl| fl[:id] }
43
43
  end
44
44
 
45
+ # @return [String] provisions a new public IP address in target region
46
+ # TODO nil if none available
47
+ def provision_public_ip_address
48
+ address = fog_compute.addresses.create
49
+ address.public_ip
50
+ # TODO catch error and return nil
51
+ end
52
+
53
+ def associate_ip_address_with_server(ip_address, server)
54
+ address = fog_compute.addresses.get(ip_address)
55
+ address.server = server
56
+ end
57
+
45
58
  # Creates or reuses an AWS security group and opens ports.
46
59
  #
47
60
  # +security_group_name+ is the name to be created or reused
@@ -74,4 +87,26 @@ class Bosh::Providers::AWS < Bosh::Providers::BaseProvider
74
87
  def port_open?(ip_permissions, port)
75
88
  ip_permissions && ip_permissions.find {|ip| ip["fromPort"] <= port && ip["toPort"] >= port }
76
89
  end
90
+
91
+ def find_server_device(server, device)
92
+ server.volumes.all.find {|v| v.device == device}
93
+ end
94
+
95
+ def create_and_attach_volume(name, disk_size, server, device)
96
+ volume = fog_compute.volumes.create(
97
+ size: disk_size,
98
+ name: name,
99
+ description: '',
100
+ device: device,
101
+ availability_zone: server.availability_zone)
102
+ # TODO: the following works in fog 1.9.0+ (but which has a bug in bootstrap)
103
+ # https://github.com/fog/fog/issues/1516
104
+ #
105
+ # volume.wait_for { volume.status == 'available' }
106
+ # volume.attach(server.id, "/dev/vdc")
107
+ # volume.wait_for { volume.status == 'in-use' }
108
+ #
109
+ # Instead, using:
110
+ volume.server = server
111
+ end
77
112
  end
@@ -9,12 +9,7 @@ class Bosh::Providers::BaseProvider
9
9
  @fog_compute = fog_compute
10
10
  end
11
11
 
12
- # @return [String] provisions a new public IP address in target region
13
- # TODO nil if none available
14
- def provision_public_ip_address
15
- address = fog_compute.addresses.create
16
- address.public_ip
17
- # TODO catch error and return nil
12
+ def create_key_pair(key_pair_name)
13
+ fog_compute.key_pairs.create(:name => key_pair_name)
18
14
  end
19
-
20
15
  end
@@ -5,6 +5,19 @@ module Bosh; module Providers; end; end
5
5
  require "bosh/providers/base_provider"
6
6
 
7
7
  class Bosh::Providers::OpenStack < Bosh::Providers::BaseProvider
8
+ # @return [String] provisions a new public IP address in target region
9
+ # TODO nil if none available
10
+ def provision_public_ip_address
11
+ address = fog_compute.addresses.create
12
+ address.ip
13
+ # TODO catch error and return nil
14
+ end
15
+
16
+ def associate_ip_address_with_server(ip_address, server)
17
+ address = fog_compute.addresses.find { |a| a.ip == ip_address }
18
+ address.server = server
19
+ end
20
+
8
21
  # Creates or reuses an OpenStack security group and opens ports.
9
22
  #
10
23
  # +security_group_name+ is the name to be created or reused
@@ -15,13 +28,14 @@ class Bosh::Providers::OpenStack < Bosh::Providers::BaseProvider
15
28
  # https: 443
16
29
  # }
17
30
  def create_security_group(security_group_name, description, ports)
18
- unless sg = fog_compute.security_groups.get(security_group_name)
31
+ security_groups = fog_compute.security_groups
32
+ unless sg = security_groups.find { |s| s.name == security_group_name }
19
33
  sg = fog_compute.security_groups.create(name: security_group_name, description: description)
20
34
  puts "Created security group #{security_group_name}"
21
35
  else
22
36
  puts "Reusing security group #{security_group_name}"
23
37
  end
24
- ip_permissions = sg.ip_permissions
38
+ ip_permissions = sg.rules
25
39
  ports_opened = 0
26
40
  ports.each do |name, port|
27
41
  unless port_open?(ip_permissions, port)
@@ -35,6 +49,21 @@ class Bosh::Providers::OpenStack < Bosh::Providers::BaseProvider
35
49
  end
36
50
 
37
51
  def port_open?(ip_permissions, port)
38
- ip_permissions && ip_permissions.find {|ip| ip["fromPort"] <= port && ip["toPort"] >= port }
52
+ ip_permissions && ip_permissions.find {|ip| ip["from_port"] <= port && ip["to_port"] >= port }
53
+ end
54
+
55
+ def find_server_device(server, device)
56
+ va = fog_compute.get_server_volumes(server.id).body['volumeAttachments']
57
+ va.find { |v| v["device"] == device }
58
+ end
59
+
60
+ def create_and_attach_volume(name, disk_size, server, device)
61
+ volume = fog_compute.volumes.create(:name => name,
62
+ :description => "",
63
+ :size => disk_size,
64
+ :availability_zone => server.availability_zone)
65
+ volume.wait_for { volume.status == 'available' }
66
+ volume.attach(server.id, device)
67
+ volume.wait_for { volume.status == 'in-use' }
39
68
  end
40
69
  end
@@ -79,6 +79,13 @@ module Bosh::Bootstrap
79
79
  else
80
80
  confirm "No specific region/data center for #{settings.fog_credentials.provider}"
81
81
  end
82
+
83
+ unless settings["network_label"]
84
+ choose_provider_network_label
85
+ end
86
+ if settings["network_label"]
87
+ confirm "Using #{settings.fog_credentials.provider} network labelled #{settings['network_label']}"
88
+ end
82
89
  end
83
90
 
84
91
  def deploy_stage_2_bosh_configuration
@@ -101,6 +108,12 @@ module Bosh::Bootstrap
101
108
  end
102
109
  confirm "After BOSH is created, your username will be #{settings.bosh_username}"
103
110
 
111
+ unless settings[:bosh_resources_cloud_properties]
112
+ settings[:bosh_resources_cloud_properties] = bosh_resources_cloud_properties
113
+ save_settings!
114
+ end
115
+ confirm "Micro BOSH instance type will be #{settings[:bosh_resources_cloud_properties]["instance_type"]}"
116
+
104
117
  unless settings[:bosh]
105
118
  say "Defaulting to 16Gb persistent disk for BOSH"
106
119
  password = settings.bosh_password # FIXME dual use of password?
@@ -109,6 +122,7 @@ module Bosh::Bootstrap
109
122
  settings[:bosh][:persistent_disk] = 16384
110
123
  save_settings!
111
124
  end
125
+
112
126
  unless settings[:bosh]["ip_address"]
113
127
  say "Acquiring IP address for micro BOSH..."
114
128
  ip_address = acquire_ip_address
@@ -409,7 +423,8 @@ module Bosh::Bootstrap
409
423
  "openstack_username" => profile[:openstack_username],
410
424
  "openstack_api_key" => profile[:openstack_api_key],
411
425
  "openstack_tenant" => profile[:openstack_tenant],
412
- "openstack_auth_url" => profile[:openstack_auth_url]
426
+ "openstack_auth_url" => profile[:openstack_auth_url],
427
+ "openstack_region" => profile[:openstack_region]
413
428
  }
414
429
  end
415
430
  end
@@ -431,7 +446,6 @@ module Bosh::Bootstrap
431
446
  settings[:fog_credentials][key] = value
432
447
  end
433
448
  setup_bosh_cloud_properties
434
- settings[:bosh_resources_cloud_properties] = bosh_resources_cloud_properties
435
449
  settings[:bosh_provider] = settings.bosh_cloud_properties.keys.first # aws, vsphere...
436
450
  save_settings!
437
451
  end
@@ -502,13 +516,24 @@ module Bosh::Bootstrap
502
516
  if aws?
503
517
  {"instance_type" => "m1.medium"}
504
518
  elsif openstack?
505
- # TODO: Ask for instance type
506
- {"instance_type" => "m1.medium"}
519
+ {"instance_type" => choose_bosh_openstack_flavor}
507
520
  else
508
521
  raise "implement #bosh_resources_cloud_properties for #{settings.fog_credentials.provider}"
509
522
  end
510
523
  end
511
524
 
525
+ def choose_bosh_openstack_flavor
526
+ say ""
527
+ hl.choose do |menu|
528
+ menu.prompt = "Choose Micro BOSH instance type: "
529
+ fog_compute.flavors.each do |flavor|
530
+ menu.choice(flavor.name) do
531
+ return flavor.name
532
+ end
533
+ end
534
+ end
535
+ end
536
+
512
537
  # Ask user to provide region information (URI)
513
538
  # or choose from a known list of regions (e.g. AWS)
514
539
  # Return true if region selected (@region_code is set)
@@ -517,8 +542,8 @@ module Bosh::Bootstrap
517
542
  if aws?
518
543
  choose_aws_region
519
544
  else
520
- settings["region_code"] = nil
521
- false
545
+ return false if settings.has_key?("region_code")
546
+ prompt_openstack_region
522
547
  end
523
548
  end
524
549
 
@@ -543,6 +568,29 @@ module Bosh::Bootstrap
543
568
  true
544
569
  end
545
570
 
571
+ def prompt_openstack_region
572
+ default_region = settings.fog_credentials.openstack_region
573
+ region = hl.ask("OpenStack Region (optional): ") { |q| q.default = default_region }
574
+ settings[:region_code] = region.strip == "" ? nil : region
575
+ return false unless settings[:region_code]
576
+
577
+ settings["fog_credentials"]["openstack_region"] = settings[:region_code]
578
+ settings["bosh_cloud_properties"]["openstack"]["region"] = settings[:region_code]
579
+ save_settings!
580
+ reset_fog_compute
581
+ true
582
+ end
583
+
584
+ def choose_provider_network_label
585
+ if openstack?
586
+ prompt_openstack_network_label
587
+ end
588
+ end
589
+
590
+ def prompt_openstack_network_label
591
+ settings[:network_label] = hl.ask("OpenStack private network label: ") { |q| q.default = "private" }
592
+ end
593
+
546
594
  # Creates a security group.
547
595
  # Also sets up the bosh_cloud_properties for the remote server
548
596
  #
@@ -574,19 +622,7 @@ module Bosh::Bootstrap
574
622
  save_settings!
575
623
  end
576
624
 
577
- # Creates a key pair.
578
- def create_key_pair(key_pair_name)
579
- if aws?
580
- create_aws_key_pair(key_pair_name)
581
- elsif openstack?
582
- create_openstack_key_pair(key_pair_name)
583
- else
584
- raise "implement #create_key_pair for #{settings.fog_credentials.provider}"
585
- end
586
- end
587
-
588
- # Creates an AWS key pair, and stores the private key
589
- # in settings manifest.
625
+ # Creates a key pair, and stores the private key in settings manifest.
590
626
  # Also sets up the bosh_cloud_properties for the remote server
591
627
  # to have the .pem key installed.
592
628
  #
@@ -594,48 +630,30 @@ module Bosh::Bootstrap
594
630
  # * bosh_key_pair.name
595
631
  # * bosh_key_pair.private_key
596
632
  # * bosh_key_pair.fingerprint
633
+ # For AWS:
597
634
  # * bosh_cloud_properties.aws.default_key_name
598
635
  # * bosh_cloud_properties.aws.ec2_private_key
599
- def create_aws_key_pair(key_pair_name)
600
- unless fog_compute.key_pairs.get(key_pair_name)
601
- say "creating key pair #{key_pair_name}..."
602
- kp = fog_compute.key_pairs.create(:name => key_pair_name)
603
- settings[:bosh_key_pair] = {}
604
- settings[:bosh_key_pair][:name] = key_pair_name
605
- settings[:bosh_key_pair][:private_key] = kp.private_key
606
- settings[:bosh_key_pair][:fingerprint] = kp.fingerprint
607
- settings["bosh_cloud_properties"]["aws"]["default_key_name"] = key_pair_name
608
- settings["bosh_cloud_properties"]["aws"]["ec2_private_key"] = "/home/vcap/.ssh/#{key_pair_name}.pem"
609
- save_settings!
610
- else
611
- error "AWS key pair '#{key_pair_name}' already exists. Rename BOSH or delete old key pair manually and re-run CLI."
612
- end
613
- end
614
-
615
- # Creates an OpenStack key pair, and stores the private key
616
- # in settings manifest.
617
- # Also sets up the bosh_cloud_properties for the remote server
618
- # to have the .pem key installed.
619
- #
620
- # Adds settings:
621
- # * bosh_key_pair.name
622
- # * bosh_key_pair.private_key
623
- # * bosh_key_pair.fingerprint
636
+ # For OpenStack:
624
637
  # * bosh_cloud_properties.openstack.default_key_name
625
- # * bosh_cloud_properties.openstack.ec2_private_key
626
- def create_openstack_key_pair(key_pair_name)
638
+ # * bosh_cloud_properties.openstack.private_key
639
+ def create_key_pair(key_pair_name)
627
640
  unless fog_compute.key_pairs.get(key_pair_name)
628
641
  say "creating key pair #{key_pair_name}..."
629
- kp = fog_compute.key_pairs.create(:name => key_pair_name)
642
+ kp = provider.create_key_pair(key_pair_name)
630
643
  settings[:bosh_key_pair] = {}
631
644
  settings[:bosh_key_pair][:name] = key_pair_name
632
645
  settings[:bosh_key_pair][:private_key] = kp.private_key
633
646
  settings[:bosh_key_pair][:fingerprint] = kp.fingerprint
634
- settings["bosh_cloud_properties"]["openstack"]["default_key_name"] = key_pair_name
635
- settings["bosh_cloud_properties"]["openstack"]["private_key"] = "/home/vcap/.ssh/#{key_pair_name}.pem"
647
+ if aws?
648
+ settings["bosh_cloud_properties"]["aws"]["default_key_name"] = key_pair_name
649
+ settings["bosh_cloud_properties"]["aws"]["ec2_private_key"] = "/home/vcap/.ssh/#{key_pair_name}.pem"
650
+ elsif openstack?
651
+ settings["bosh_cloud_properties"]["openstack"]["default_key_name"] = key_pair_name
652
+ settings["bosh_cloud_properties"]["openstack"]["private_key"] = "/home/vcap/.ssh/#{key_pair_name}.pem"
653
+ end
636
654
  save_settings!
637
655
  else
638
- error "OpenStack key pair '#{key_pair_name}' already exists. Rename BOSH or delete old key pair manually and re-run CLI."
656
+ error "Key pair '#{key_pair_name}' already exists. Rename BOSH or delete old key pair manually and re-run CLI."
639
657
  end
640
658
  end
641
659
 
@@ -733,51 +751,52 @@ module Bosh::Bootstrap
733
751
  end
734
752
  confirm "Using key pair #{key_pair.name} for Inception VM"
735
753
 
736
- # make sure port 22 is open in the default security group
737
- security_group = fog_compute.security_groups.find { |sg| sg.name == 'default' }
738
- authorized = security_group.rules.detect do |ip_permission|
739
- ip_permission['ip_range'].first && ip_permission['ip_range']['cidr'] == '0.0.0.0/0' &&
740
- ip_permission['from_port'] == 22 &&
741
- ip_permission['ip_protocol'] == 'tcp' &&
742
- ip_permission['to_port'] == 22
743
- end
744
- unless authorized
745
- security_group.create_security_group_rule(22, 22)
746
- end
747
- confirm "Inception VM port 22 open"
748
-
749
754
  unless settings["inception"] && settings["inception"]["server_id"]
750
755
  username = "ubuntu"
751
756
  say "Provisioning server for inception VM..."
752
- settings["inception"] = {}
757
+ settings["inception"] ||= {}
753
758
 
754
759
  # Select OpenStack flavor
760
+ if settings["inception"]["flavor_id"]
761
+ inception_flavor = fog_compute.flavors.find { |f| f.id == settings["inception"]["flavor_id"] }
762
+ settings["inception"]["flavor_id"] = nil if inception_flavor.nil?
763
+ end
755
764
  unless settings["inception"]["flavor_id"]
756
765
  say ""
757
766
  hl.choose do |menu|
758
767
  menu.prompt = "Choose OpenStack flavor: "
759
768
  fog_compute.flavors.each do |flavor|
760
769
  menu.choice(flavor.name) do
761
- settings["inception"]["flavor_id"] = flavor.id
770
+ inception_flavor = flavor
771
+ settings["inception"]["flavor_id"] = inception_flavor.id
762
772
  save_settings!
763
773
  end
764
774
  end
765
775
  end
766
776
  end
777
+ say ""
778
+ confirm "Using flavor #{inception_flavor.name} for Inception VM"
767
779
 
768
780
  # Select OpenStack image
781
+ if settings["inception"]["image_id"]
782
+ inception_image = fog_compute.images.find { |i| i.id == settings["inception"]["image_id"] }
783
+ settings["inception"]["image_id"] = nil if inception_image.nil?
784
+ end
769
785
  unless settings["inception"]["image_id"]
770
786
  say ""
771
787
  hl.choose do |menu|
772
788
  menu.prompt = "Choose OpenStack image (Ubuntu): "
773
789
  fog_compute.images.each do |image|
774
790
  menu.choice(image.name) do
775
- settings["inception"]["image_id"] = image.id
791
+ inception_image = image
792
+ settings["inception"]["image_id"] = inception_image.id
776
793
  save_settings!
777
794
  end
778
795
  end
779
796
  end
780
797
  end
798
+ say ""
799
+ confirm "Using image #{inception_image.name} for Inception VM"
781
800
 
782
801
  # Boot OpenStack server
783
802
  server = fog_compute.servers.create(
@@ -785,8 +804,8 @@ module Bosh::Bootstrap
785
804
  :key_name => key_pair.name,
786
805
  :public_key_path => public_key_path,
787
806
  :private_key_path => private_key_path,
788
- :flavor_ref => settings["inception"]["flavor_id"],
789
- :image_ref => settings["inception"]["image_id"],
807
+ :flavor_ref => inception_flavor.id,
808
+ :image_ref => inception_image.id,
790
809
  :username => username
791
810
  )
792
811
  unless server
@@ -810,6 +829,19 @@ module Bosh::Bootstrap
810
829
  save_settings!
811
830
  end
812
831
 
832
+ # TODO: Hack
833
+ unless server.public_ip_address
834
+ server.addresses["public"] = [settings["inception"]["ip_address"]]
835
+ end
836
+ unless server.public_key_path
837
+ server.public_key_path = public_key_path
838
+ end
839
+ unless server.private_key_path
840
+ server.private_key_path = private_key_path
841
+ end
842
+ server.username = settings["inception"]["username"]
843
+ Fog.wait_for(60) { server.sshable? }
844
+
813
845
  unless settings["inception"]["disk_size"]
814
846
  disk_size = DEFAULT_INCEPTION_VOLUME_SIZE # Gb
815
847
  device = "/dev/vdc"
@@ -818,44 +850,6 @@ module Bosh::Bootstrap
818
850
  settings["inception"]["disk_size"] = disk_size
819
851
  settings["inception"]["disk_device"] = device
820
852
  save_settings!
821
-
822
- # TODO use provision_and_mount_volume
823
-
824
- disk_size = 16 # Gb
825
- va = fog_compute.get_server_volumes(server.id).body['volumeAttachments']
826
- unless vol = va.find { |v| v["device"] == "/dev/vdc" }
827
- say "Provisioning #{disk_size}Gb persistent disk for inception VM..."
828
- volume = fog_compute.volumes.create(:name => "Inception Disk",
829
- :description => "",
830
- :size => disk_size,
831
- :availability_zone => server.availability_zone)
832
- volume.wait_for { volume.status == 'available' }
833
- volume.attach(server.id, "/dev/vdc")
834
- volume.wait_for { volume.status == 'in-use' }
835
- end
836
-
837
- # Format and mount the volume
838
- # TODO: Hack
839
- unless server.public_ip_address
840
- server.addresses["public"] = [settings["inception"]["ip_address"]]
841
- end
842
- unless server.public_key_path
843
- server.public_key_path = public_key_path
844
- end
845
- unless server.private_key_path
846
- server.private_key_path = private_key_path
847
- end
848
- server.username = settings["inception"]["username"]
849
- server.sshable?
850
-
851
- say "Mounting persistent disk as volume on inception VM..."
852
- # TODO if any of these ssh calls fail; retry
853
- server.ssh(['sudo mkfs.ext4 /dev/vdc -F'])
854
- server.ssh(['sudo mkdir -p /var/vcap/store'])
855
- server.ssh(['sudo mount /dev/vdc /var/vcap/store'])
856
-
857
- settings["inception"]["disk_size"] = disk_size
858
- save_settings!
859
853
  end
860
854
 
861
855
  # settings["inception"]["host"] is used externally to determine
@@ -884,8 +878,7 @@ module Bosh::Bootstrap
884
878
  end
885
879
 
886
880
  def associate_ip_address_with_server(ip_address, server)
887
- address = fog_compute.addresses.get(ip_address)
888
- address.server = server
881
+ provider.associate_ip_address_with_server(ip_address, server)
889
882
  server.reload
890
883
  end
891
884
 
@@ -894,23 +887,9 @@ module Bosh::Bootstrap
894
887
  #
895
888
  # Requires that we can SSH into +server+.
896
889
  def provision_and_mount_volume(server, disk_size, device)
897
- unless volume = server.volumes.all.find {|v| v.device == device}
890
+ unless provider.find_server_device(server, device)
898
891
  say "Provisioning #{disk_size}Gb persistent disk for inception VM..."
899
- volume = fog_compute.volumes.create(
900
- size: disk_size,
901
- name: "Inception Disk",
902
- description: '',
903
- device: "/dev/sdi",
904
- availability_zone: server.availability_zone)
905
- # TODO: the following works in fog 1.9.0+ (but which has a bug in bootstrap)
906
- # https://github.com/fog/fog/issues/1516
907
- #
908
- # volume.wait_for { volume.status == 'available' }
909
- # volume.attach(server.id, "/dev/vdc")
910
- # volume.wait_for { volume.status == 'in-use' }
911
- #
912
- # Instead, using:
913
- volume.server = server
892
+ provider.create_and_attach_volume("Inception Disk", disk_size, server, device)
914
893
  end
915
894
 
916
895
  # Format and mount the volume
@@ -79,7 +79,7 @@ module Bosh::Bootstrap::Stages
79
79
  # ec2_private_key: /home/vcap/.ssh/#{key_name}.pem
80
80
  cloud_properties = settings.bosh_cloud_properties
81
81
 
82
- {
82
+ manifest = {
83
83
  "name" => name,
84
84
  "env" => { "bosh" => {"password" => salted_password}},
85
85
  "logging" => { "level" => "DEBUG" },
@@ -101,7 +101,20 @@ module Bosh::Bootstrap::Stages
101
101
  "#{cloud_plugin.downcase}_registry" => { "address" => ipaddress }
102
102
  }
103
103
  }
104
- }.to_yaml.gsub(/\s![^ ]+$/, '')
104
+ }
105
+
106
+ # Openstack settings
107
+ if cloud_plugin.downcase == "openstack"
108
+ # Delete OpenStack registry IP address
109
+ manifest["apply_spec"]["properties"].delete("openstack_registry")
110
+
111
+ # OpenStack private network label
112
+ if settings.network_label
113
+ manifest["network"]["label"] = settings.network_label
114
+ end
115
+ end
116
+
117
+ manifest.to_yaml.gsub(/\s![^ ]+$/, '')
105
118
 
106
119
  # /![^ ]+\s/ removes object notation from the YAML which appears to cause problems when being interpretted by the
107
120
  # Ruby running on the inception vm. A before and after example would look like;
@@ -1,5 +1,5 @@
1
1
  module Bosh
2
2
  module Bootstrap
3
- VERSION = "0.5.0"
3
+ VERSION = "0.5.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh-bootstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-27 00:00:00.000000000 Z
12
+ date: 2013-01-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor