bosh-cloudfoundry 0.2.0
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.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +6 -0
- data/Guardfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +242 -0
- data/Rakefile +33 -0
- data/bosh-cloudfoundry.gemspec +29 -0
- data/config/defaults.yml +6 -0
- data/lib/bosh-cloudfoundry.rb +34 -0
- data/lib/bosh-cloudfoundry/bosh_release_manager.rb +141 -0
- data/lib/bosh-cloudfoundry/config.rb +6 -0
- data/lib/bosh-cloudfoundry/config/common_config.rb +27 -0
- data/lib/bosh-cloudfoundry/config/dea_config.rb +150 -0
- data/lib/bosh-cloudfoundry/config/microbosh_config.rb +106 -0
- data/lib/bosh-cloudfoundry/config/postgresql_service_config.rb +185 -0
- data/lib/bosh-cloudfoundry/config/redis_service_config.rb +179 -0
- data/lib/bosh-cloudfoundry/config/system_config.rb +60 -0
- data/lib/bosh-cloudfoundry/config_options.rb +362 -0
- data/lib/bosh-cloudfoundry/gerrit_patches_helper.rb +47 -0
- data/lib/bosh-cloudfoundry/providers.rb +19 -0
- data/lib/bosh-cloudfoundry/providers/aws.rb +75 -0
- data/lib/bosh-cloudfoundry/system_deployment_manifest_renderer.rb +286 -0
- data/lib/bosh-cloudfoundry/version.rb +5 -0
- data/lib/bosh/cli/commands/cf.rb +668 -0
- data/spec/assets/.gitkeep +0 -0
- data/spec/assets/cf-release/jobs/cloud_controller/templates/runtimes.yml +150 -0
- data/spec/assets/deployments/aws-core-1-m1.small-free-redis.yml +221 -0
- data/spec/assets/deployments/aws-core-1-m1.xlarge-free-postgresql-2-m1.small-free-postgresql.yml +248 -0
- data/spec/assets/deployments/aws-core-2-m1.xlarge-dea.yml +195 -0
- data/spec/assets/deployments/aws-core-only.yml +178 -0
- data/spec/assets/deployments/aws-core-with-nfs.yml +192 -0
- data/spec/functional/.gitkeep +0 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/unit/.gitkeep +0 -0
- data/spec/unit/bosh_release_manager_spec.rb +36 -0
- data/spec/unit/cf_command_spec.rb +280 -0
- data/spec/unit/config/common_config_spec.rb +21 -0
- data/spec/unit/config/dea_config_spec.rb +92 -0
- data/spec/unit/config/microbosh_config_spec.rb +11 -0
- data/spec/unit/config/postgresql_service_config_spec.rb +103 -0
- data/spec/unit/config/redis_service_config_spec.rb +103 -0
- data/spec/unit/config/system_config_spec.rb +29 -0
- data/spec/unit/config_options_spec.rb +64 -0
- data/spec/unit/system_deployment_manifest_renderer_spec.rb +93 -0
- metadata +246 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
require "bosh-cloudfoundry/config/common_config"
|
2
|
+
require "bosh-cloudfoundry/config/system_config"
|
3
|
+
require "bosh-cloudfoundry/config/microbosh_config"
|
4
|
+
require "bosh-cloudfoundry/config/dea_config"
|
5
|
+
require "bosh-cloudfoundry/config/postgresql_service_config"
|
6
|
+
require "bosh-cloudfoundry/config/redis_service_config"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright (c) 2012-2013 Stark & Wayne, LLC
|
2
|
+
|
3
|
+
module Bosh; module CloudFoundry; module Config; end; end; end
|
4
|
+
|
5
|
+
module Bosh::CloudFoundry::Config
|
6
|
+
class CommonConfig < Bosh::Cli::Config
|
7
|
+
|
8
|
+
[
|
9
|
+
:base_systems_dir, # e.g. /var/vcap/store/systems
|
10
|
+
:target_system, # e.g. /var/vcap/store/systems/production
|
11
|
+
:cf_release_git_repo, # e.g. "git://github.com/cloudfoundry/cf-release.git"
|
12
|
+
:bosh_git_repo, # e.g. "git://github.com/cloudfoundry/bosh.git"
|
13
|
+
:releases_dir, # e.g. /var/vcap/store/releases
|
14
|
+
:cf_release_dir, # e.g. /var/vcap/store/releases/cf-release
|
15
|
+
:stemcells_dir, # e.g. /var/vcap/store/stemcells
|
16
|
+
:repos_dir, # e.g. /var/vcap/store/repos
|
17
|
+
].each do |attr|
|
18
|
+
define_method attr do
|
19
|
+
read(attr, false)
|
20
|
+
end
|
21
|
+
|
22
|
+
define_method "#{attr}=" do |value|
|
23
|
+
write_global(attr, value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# Copyright (c) 2012-2013 Stark & Wayne, LLC
|
2
|
+
|
3
|
+
module Bosh; module CloudFoundry; module Config; end; end; end
|
4
|
+
|
5
|
+
class Bosh::CloudFoundry::Config::DeaConfig
|
6
|
+
attr_reader :system_config
|
7
|
+
|
8
|
+
def initialize(system_config)
|
9
|
+
@system_config = system_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.build_from_system_config(system_config)
|
13
|
+
system_config.dea ||= {}
|
14
|
+
new(system_config)
|
15
|
+
end
|
16
|
+
|
17
|
+
def bosh_provider_name
|
18
|
+
@system_config.bosh_provider
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_count_and_flavor(server_count, server_flavor)
|
22
|
+
self.dea_server_count = server_count.to_i
|
23
|
+
self.dea_server_flavor = server_flavor.to_s
|
24
|
+
self.save
|
25
|
+
end
|
26
|
+
|
27
|
+
# Determine ow many DEA servers are required
|
28
|
+
# based on the system configuration
|
29
|
+
def dea_server_count
|
30
|
+
@system_config.dea["count"] || 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def dea_server_count=(count)
|
34
|
+
@system_config.dea["count"] = count
|
35
|
+
end
|
36
|
+
|
37
|
+
def dea_server_flavor
|
38
|
+
@system_config.dea["flavor"]
|
39
|
+
end
|
40
|
+
|
41
|
+
def dea_server_flavor=(flavor)
|
42
|
+
@system_config.dea["flavor"] = flavor
|
43
|
+
end
|
44
|
+
|
45
|
+
def save
|
46
|
+
@system_config.save
|
47
|
+
end
|
48
|
+
|
49
|
+
# Adds additional cf-release jobs into the core server (the core job in the manifest)
|
50
|
+
def add_core_jobs_to_manifest(manifest)
|
51
|
+
if dea_server_count == 0
|
52
|
+
@core_job ||= manifest["jobs"].find { |job| job["name"] == "core" }
|
53
|
+
@core_job["template"] << "dea"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Adds resource pools to the target manifest, if dea_server_count > 0
|
58
|
+
#
|
59
|
+
# - name: dea
|
60
|
+
# network: default
|
61
|
+
# size: 2
|
62
|
+
# stemcell:
|
63
|
+
# name: bosh-stemcell
|
64
|
+
# version: 0.6.4
|
65
|
+
# cloud_properties:
|
66
|
+
# instance_type: m1.xlarge
|
67
|
+
def add_resource_pools_to_manifest(manifest)
|
68
|
+
if dea_server_count > 0
|
69
|
+
resource_pool = {
|
70
|
+
"name" => "dea",
|
71
|
+
"network" => "default",
|
72
|
+
"size" => dea_server_count,
|
73
|
+
"stemcell" => {
|
74
|
+
"name" => @system_config.stemcell_name,
|
75
|
+
"version" => @system_config.stemcell_version
|
76
|
+
},
|
77
|
+
# TODO how to create "cloud_properties" per-provider?
|
78
|
+
"cloud_properties" => {
|
79
|
+
"instance_type" => dea_server_flavor
|
80
|
+
}
|
81
|
+
}
|
82
|
+
manifest["resource_pools"] << resource_pool
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Jobs to add to the target manifest
|
87
|
+
#
|
88
|
+
# - name: dea
|
89
|
+
# template:
|
90
|
+
# - dea
|
91
|
+
# instances: 2
|
92
|
+
# resource_pool: dea
|
93
|
+
# networks:
|
94
|
+
# - name: default
|
95
|
+
# default:
|
96
|
+
# - dns
|
97
|
+
# - gateway
|
98
|
+
def add_jobs_to_manifest(manifest)
|
99
|
+
if dea_server_count > 0
|
100
|
+
job = {
|
101
|
+
"name" => "dea",
|
102
|
+
"template" => ["dea"],
|
103
|
+
"instances" => dea_server_count,
|
104
|
+
"resource_pool" => "dea",
|
105
|
+
# TODO are these AWS-specific networks?
|
106
|
+
"networks" => [{
|
107
|
+
"name" => "default",
|
108
|
+
"default" => ["dns", "gateway"]
|
109
|
+
}]
|
110
|
+
}
|
111
|
+
manifest["jobs"] << job
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Add extra configuration properties into the manifest
|
116
|
+
# to configure the allocation of RAM to the DEA
|
117
|
+
def merge_manifest_properties(manifest)
|
118
|
+
manifest["properties"]["dea"] ||= {}
|
119
|
+
manifest["properties"]["dea"] = {
|
120
|
+
"max_memory" => max_memory
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def max_memory
|
125
|
+
if dea_server_count > 0
|
126
|
+
max_memory_for_dedicated_dea
|
127
|
+
else
|
128
|
+
512
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# @return [Integer] available ram for running CloudFoundry apps
|
133
|
+
def max_memory_for_dedicated_dea
|
134
|
+
ram_for_server_flavor - preallocated_ram
|
135
|
+
end
|
136
|
+
|
137
|
+
# @return [Integer] the ballpark ram for DEA, BOSH agent, etc
|
138
|
+
def preallocated_ram
|
139
|
+
300
|
140
|
+
end
|
141
|
+
|
142
|
+
def ram_for_server_flavor
|
143
|
+
provider.ram_for_server_flavor(dea_server_flavor)
|
144
|
+
end
|
145
|
+
|
146
|
+
# a helper object for the target BOSH provider
|
147
|
+
def provider
|
148
|
+
@provider ||= Bosh::CloudFoundry::Providers.for_bosh_provider_name(system_config)
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Copyright (c) 2012-2013 Stark & Wayne, LLC
|
2
|
+
|
3
|
+
module Bosh; module CloudFoundry; module Config; end; end; end
|
4
|
+
|
5
|
+
# Helper to create a Fog::Connection based on auto-discovery
|
6
|
+
# of the CPI credentials of a microbosh's local configuration.
|
7
|
+
#
|
8
|
+
# If ~/.bosh_deployer_config exists, it contains the location of
|
9
|
+
# the `micro_bosh.yml` for each microbosh.
|
10
|
+
class Bosh::CloudFoundry::Config::MicroboshConfig
|
11
|
+
attr_reader :deployed_microboshes, :target_bosh_host
|
12
|
+
|
13
|
+
def initialize(target_bosh_host)
|
14
|
+
@target_bosh_host = target_bosh_host
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
validate_target_bosh_host &&
|
19
|
+
validate_bosh_deployer_config
|
20
|
+
end
|
21
|
+
|
22
|
+
def fog_compute
|
23
|
+
return nil unless valid?
|
24
|
+
@fog_compute ||= Fog::Compute.new(fog_connection_properties)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fog_connection_properties
|
28
|
+
if aws?
|
29
|
+
ec2_endpoint = provider_credentials["ec2_endpoint"]
|
30
|
+
if ec2_endpoint =~ /ec2\.([\w-]+)\.amazonaws\.com/
|
31
|
+
region = $1
|
32
|
+
else
|
33
|
+
raise "please add support to extra 'region' from #{ec2_endpoint}"
|
34
|
+
end
|
35
|
+
{
|
36
|
+
provider: "aws",
|
37
|
+
region: region,
|
38
|
+
aws_access_key_id: provider_credentials["access_key_id"],
|
39
|
+
aws_secret_access_key: provider_credentials["secret_access_key"]
|
40
|
+
}
|
41
|
+
else
|
42
|
+
raise "please implement #fog_credentials for #{bosh_provider}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def bosh_provider
|
47
|
+
cloud_config["plugin"]
|
48
|
+
end
|
49
|
+
|
50
|
+
def provider_credentials
|
51
|
+
cloud_config["properties"][bosh_provider]
|
52
|
+
end
|
53
|
+
|
54
|
+
def aws?
|
55
|
+
bosh_provider == "aws"
|
56
|
+
end
|
57
|
+
|
58
|
+
# micro_bosh.yml looks like:
|
59
|
+
#
|
60
|
+
# cloud:
|
61
|
+
# plugin: aws
|
62
|
+
# properties:
|
63
|
+
# aws:
|
64
|
+
# access_key_id: ACCESS
|
65
|
+
# secret_access_key: SECRET
|
66
|
+
# ec2_endpoint: ec2.us-east-1.amazonaws.com
|
67
|
+
# default_security_groups:
|
68
|
+
# - microbosh-aws-us-east-1
|
69
|
+
# default_key_name: microbosh-aws-us-east-1
|
70
|
+
# ec2_private_key: /home/vcap/.ssh/microbosh-aws-us-east-1.pem
|
71
|
+
def cloud_config
|
72
|
+
microbosh_config["cloud"]
|
73
|
+
end
|
74
|
+
|
75
|
+
def microbosh_config
|
76
|
+
YAML.load_file(target_microbosh_config_path)
|
77
|
+
end
|
78
|
+
|
79
|
+
# ensure input value is a valid URI
|
80
|
+
def validate_target_bosh_host
|
81
|
+
URI.parse(target_bosh_host)
|
82
|
+
true
|
83
|
+
rescue
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
87
|
+
# ensure there is a ~/.bosh_deployer_config
|
88
|
+
def validate_bosh_deployer_config
|
89
|
+
return false unless File.exist? bosh_deployer_config
|
90
|
+
@deployed_microboshes = YAML.load_file(bosh_deployer_config)
|
91
|
+
return false unless target_microbosh_config_path
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
def bosh_deployer_config
|
96
|
+
File.expand_path("~/.bosh_deployer_config")
|
97
|
+
end
|
98
|
+
|
99
|
+
# .bosh_deployer_config looks like:
|
100
|
+
#
|
101
|
+
# deployment:
|
102
|
+
# http://1.2.3.4:25555: /path/to/micro_bosh.yml
|
103
|
+
def target_microbosh_config_path
|
104
|
+
deployed_microboshes["deployment"][target_bosh_host]
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# Copyright (c) 2012-2013 Stark & Wayne, LLC
|
2
|
+
|
3
|
+
module Bosh; module CloudFoundry; module Config; end; end; end
|
4
|
+
|
5
|
+
class Bosh::CloudFoundry::Config::PostgresqlServiceConfig
|
6
|
+
|
7
|
+
def initialize(system_config)
|
8
|
+
@system_config = system_config
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.build_from_system_config(system_config)
|
12
|
+
system_config.postgresql ||= []
|
13
|
+
new(system_config)
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
@system_config.postgresql
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Boolean] true if there are any postgresql nodes to be provisioned
|
21
|
+
def any_service_nodes?
|
22
|
+
total_service_nodes_count > 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def total_service_nodes_count
|
26
|
+
config.inject(0) { |total, cluster| total + (cluster["count"].to_i) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def bosh_provider_name
|
30
|
+
@system_config.bosh_provider
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_cluster_count_for_flavor(server_count, server_flavor, server_plan="free")
|
34
|
+
if cluster = find_cluster_for_flavor(server_flavor.to_s)
|
35
|
+
cluster["count"] = server_count
|
36
|
+
else
|
37
|
+
config << {"count" => server_count, "flavor" => server_flavor.to_s, "plan" => server_plan}
|
38
|
+
end
|
39
|
+
self.save
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Hash] the Hash from @system_config for the requested flavor
|
43
|
+
# nil if its not currently a requested flavor
|
44
|
+
def find_cluster_for_flavor(server_flavor)
|
45
|
+
@system_config.postgresql.find { |cl| cl["flavor"] == server_flavor }
|
46
|
+
end
|
47
|
+
|
48
|
+
def save
|
49
|
+
@system_config.save
|
50
|
+
end
|
51
|
+
|
52
|
+
# resource_pool name for a cluster
|
53
|
+
# cluster_name like 'postgresql_m1_xlarge_free'
|
54
|
+
def cluster_name(cluster)
|
55
|
+
server_flavor = cluster["flavor"]
|
56
|
+
server_plan = cluster["plan"] || "free"
|
57
|
+
cluster_name = "postgresql_#{server_flavor}_#{server_plan}"
|
58
|
+
cluster_name.gsub!(/\W+/, '_')
|
59
|
+
cluster_name
|
60
|
+
end
|
61
|
+
|
62
|
+
# Adds "postgresql_gateway" to colocated "core" job
|
63
|
+
def add_core_jobs_to_manifest(manifest)
|
64
|
+
if any_service_nodes?
|
65
|
+
@core_job ||= manifest["jobs"].find { |job| job["name"] == "core" }
|
66
|
+
@core_job["template"] << "postgresql_gateway"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Adds resource pools to the target manifest, if server_count > 0
|
71
|
+
#
|
72
|
+
# - name: postgresql
|
73
|
+
# network: default
|
74
|
+
# size: 2
|
75
|
+
# stemcell:
|
76
|
+
# name: bosh-stemcell
|
77
|
+
# version: 0.6.4
|
78
|
+
# cloud_properties:
|
79
|
+
# instance_type: m1.xlarge
|
80
|
+
def add_resource_pools_to_manifest(manifest)
|
81
|
+
if any_service_nodes?
|
82
|
+
config.each do |cluster|
|
83
|
+
server_count = cluster["count"]
|
84
|
+
server_flavor = cluster["flavor"]
|
85
|
+
resource_pool = {
|
86
|
+
"name" => cluster_name(cluster),
|
87
|
+
"network" => "default",
|
88
|
+
"size" => server_count,
|
89
|
+
"stemcell" => {
|
90
|
+
"name" => @system_config.stemcell_name,
|
91
|
+
"version" => @system_config.stemcell_version
|
92
|
+
},
|
93
|
+
# TODO how to create "cloud_properties" per-provider?
|
94
|
+
"cloud_properties" => {
|
95
|
+
"instance_type" => server_flavor
|
96
|
+
},
|
97
|
+
"persistent_disk" => 16192
|
98
|
+
}
|
99
|
+
manifest["resource_pools"] << resource_pool
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Jobs to add to the target manifest
|
105
|
+
#
|
106
|
+
# - name: postgresql
|
107
|
+
# template:
|
108
|
+
# - postgresql
|
109
|
+
# instances: 2
|
110
|
+
# resource_pool: postgresql
|
111
|
+
# networks:
|
112
|
+
# - name: default
|
113
|
+
# default:
|
114
|
+
# - dns
|
115
|
+
# - gateway
|
116
|
+
def add_jobs_to_manifest(manifest)
|
117
|
+
if any_service_nodes?
|
118
|
+
config.each do |cluster|
|
119
|
+
server_count = cluster["count"]
|
120
|
+
server_flavor = cluster["flavor"]
|
121
|
+
job = {
|
122
|
+
"name" => cluster_name(cluster),
|
123
|
+
"template" => ["postgresql_node"],
|
124
|
+
"instances" => server_count,
|
125
|
+
"resource_pool" => cluster_name(cluster),
|
126
|
+
# TODO are these AWS-specific networks?
|
127
|
+
"networks" => [{
|
128
|
+
"name" => "default",
|
129
|
+
"default" => ["dns", "gateway"]
|
130
|
+
}],
|
131
|
+
"persistent_disk" => 16192
|
132
|
+
}
|
133
|
+
manifest["jobs"] << job
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Add extra configuration properties into the manifest
|
139
|
+
# for the gateway, node, and service plans
|
140
|
+
def merge_manifest_properties(manifest)
|
141
|
+
if any_service_nodes?
|
142
|
+
manifest["properties"]["postgresql_gateway"] = {
|
143
|
+
"admin_user"=>"psql_admin",
|
144
|
+
"admin_passwd_hash"=>nil,
|
145
|
+
"token"=>"TOKEN",
|
146
|
+
"supported_versions"=>["9.0"],
|
147
|
+
"version_aliases"=>{"current"=>"9.0"}
|
148
|
+
}
|
149
|
+
manifest["properties"]["postgresql_node"] = {
|
150
|
+
"admin_user"=>"psql_admin",
|
151
|
+
"admin_passwd_hash"=>nil,
|
152
|
+
"available_storage"=>2048,
|
153
|
+
"max_db_size"=>256,
|
154
|
+
"max_long_tx"=>30,
|
155
|
+
"supported_versions"=>["9.0"],
|
156
|
+
"default_version"=>"9.0"
|
157
|
+
}
|
158
|
+
manifest["properties"]["service_plans"]["postgresql"] = {
|
159
|
+
"free"=>
|
160
|
+
{"job_management"=>{"high_water"=>1400, "low_water"=>100},
|
161
|
+
"configuration"=>
|
162
|
+
{"capacity"=>200,
|
163
|
+
"max_db_size"=>128,
|
164
|
+
"max_long_query"=>3,
|
165
|
+
"max_long_tx"=>30,
|
166
|
+
"max_clients"=>20,
|
167
|
+
"backup"=>{"enable"=>true}}}
|
168
|
+
}
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# @return [Integer] the ballpark ram for postgresql, BOSH agent, etc
|
173
|
+
def preallocated_ram
|
174
|
+
300
|
175
|
+
end
|
176
|
+
|
177
|
+
def ram_for_server_flavor
|
178
|
+
provider.ram_for_server_flavor(server_flavor)
|
179
|
+
end
|
180
|
+
|
181
|
+
# a helper object for the target BOSH provider
|
182
|
+
def provider
|
183
|
+
@provider ||= Bosh::CloudFoundry::Providers.for_bosh_provider_name(system_config)
|
184
|
+
end
|
185
|
+
end
|