New system-wide configuration based on YAML

This CL adds a YAML based configuration mechanism for system-wide configuration
rather than my old method. It modifies the build/release scripts to deliver
both, but the other scripts only support the old style for now so I can add
this incrementally. However, you can start things manually and it will work
using the new configuration as described below.

The config/*.yml files get installed to /opt/spinnaker/config. These are intended
to be read-only. There is a new file spinnaker.yml that acts as a global master
that all the individual systems draw from. Then a user adds a
~/.spinnaker/spinnaker-local.yml that overrides the standard places.
Where multiple accounts or different profiles are desired, you'd still need
to override the system-specific -local.yml, at least for now.

There is a sample-spinnaker-local.yml file which is an example of a file,
pretty much what I used to test this  (did not test igor or rush yet)

Services startup if you do this:

export SPRING_CONFIG_LOCATION=/opt/spinnaker/config/spinnaker.yml,/opt/spinnaker/config/,/root/.spinnaker/spinnaker-local.yml,/root/.spinnaker/

Then in the /opt/<service>/bin/<service> add:
DEFAULT_JVM_OPTS='"-Djava.security.egd=file:/dev/./urandom" "-Dspring.config.location=$SPRING_CONFIG_LOCATION"'

And need to add rush.yml as $HOME/.spinnaker/rush-local.yml
because rush doesnt look for config files the same way as everything else.

Using the existing build/installation scripts, this will pass the integration
tests but you need to manually start everything up because start_spinnaker.sh
is enforcing the old method. I'll fix that in a followup cl.

sudo bash
cd /opt/spinnaker
/opt/gce-kms/bin/gce-kms >& logs/gce_kms.out &
for i in clouddriver echo front50-web orca rush rosco ; do /opt/$i/bin/$i >& logs/$i.out
done
/opt/gate/bin/gate >& logs/gate.out &
This commit is contained in:
Eric Wiseblatt 2015-10-15 02:17:44 +00:00
Родитель 8e7d3e6c8d
Коммит a902f28b8a
28 изменённых файлов: 490 добавлений и 30 удалений

Просмотреть файл

@ -0,0 +1,22 @@
server:
port: ${services.clouddriver.port:7002}
address: ${services.clouddriver.host:localhost}
#circular
#services:
# front50:
# baseUrl: ${services.front50.baseUrl:localhost:8080}
redis:
connection: ${services.redis.connection:redis://localhost:6379}
aws:
enabled: ${providers.aws.enabled:false}
google:
enabled: ${providers.google.enabled:false}
kmsServer: ${services.gce_kms.baseUrl:http://localhost:7909}
accounts:
- name: ${providers.google.primaryCredentials.name}
project: ${providers.google.primaryCredentials.project}

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,55 @@
'use strict';
let gateHost = '${services.gate.host}:${services.gate.port}';
window.spinnakerSettings = {
gateUrl: `${services.gate.baseUrl}`,
bakeryDetailUrl: '${services.bakery.baseUrl}/api/v1/global/logs/{{context.status.id}}?html=true',
pollSchedule: 30000,
defaultTimeZone: 'America/New_York', // see http://momentjs.com/timezone/docs/#/data-utilities/
providers: {
gce: {
defaults: {
account: '${providers.google.primaryCredentials.name}',
region: '${providers.google.defaultRegion}',
zone: '${providers.google.defaultZone}',
},
primaryAccounts: ['${providers.google.primaryCredentials.name}'],
challengeDestructiveActions: ['${providers.google.primaryCredentials.name}'],
},
aws: {
defaults: {
account: '${providers.aws.primaryCredentials.name}',
region: '${providers.aws.defaultRegion}',
},
primaryAccounts: ['${providers.aws.primaryCredentials.name}]',
primaryRegions: ['eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2'],
challengeDestructiveActions: ['${providers.aws.primaryCredentials.name}'],
preferredZonesByAccount: {
${providers.aws.primaryCredentials.name}: {
'us-east-1': ['us-east-1a', 'us-east-1b', 'us-east-1d', 'us-east-1e'],
'us-west-1': ['us-west-1a', 'us-west-1b', 'us-west-1c'],
'us-west-2': ['us-west-2a', 'us-west-2b', 'us-west-2c'],
'eu-west-1': ['eu-west-1a', 'eu-west-1b', 'eu-west-1c'],
'ap-northeast-1': ['ap-northeast-1a', 'ap-northeast-1b', 'ap-northeast-1c'],
'ap-southeast-1': ['ap-southeast-1a', 'ap-southeast-1b'],
'ap-southeast-2': ['ap-southeast-2a', 'ap-southeast-2b'],
'sa-east-1': ['sa-east-1a', 'sa-east-1b']
}
}
}
},
whatsNew: {
gistId: '32526cd608db3d811b38',
fileName: 'news.md',
},
authEnabled: false,
feature: {
pipelines: true,
notifications: false,
canary: false,
parallelPipelines: true,
fastProperty: false,
vpcMigrator: true,
},
};

15
google/config/echo.yml Normal file
Просмотреть файл

@ -0,0 +1,15 @@
server:
port: ${services.echo.port:8089}
address: ${services.echo.host:localhost}
cassandra:
embedded: ${services.cassandra.embedded:false}
host: ${services.cassandra.host:localhost}
front50:
baseUrl: ${services.front50.baseUrl:http://localhost:8080}
orca:
baseUrl: ${services.orca.baseUrl:http://localhost:8083}
endpoints.health.sensitive: false

20
google/config/front50.yml Normal file
Просмотреть файл

@ -0,0 +1,20 @@
server:
port: ${services.front50.port:7002}
address: ${services.front50.host:localhost}
cassandra:
embedded: ${services.cassandra.embedded:false}
host: ${services.cassandra.host:localhost}
aws:
simpleDBEnabled: ${providers.aws.simpleDBEnabled:false}
defaultSimpleDBDomain: ${providers.aws.defaultSimpleDBDomain}
spinnaker:
cassandra:
enabled: true
host: ${services.cassandra.host:localhost}
port: ${services.cassandra.port:9042}
cluster: ${services.cassandra.cluster:CASS_SPINNAKER}
keyspace: front50
name: global

29
google/config/gate.yml Normal file
Просмотреть файл

@ -0,0 +1,29 @@
server:
port: ${services.gate.port:8084}
address: ${services.gate.host:localhost}
# Circular references since we're already using 'services'
# services:
# oort:
# baseUrl: ${services.oort.baseUrl:localhost:7002}
# orca:
# baseUrl: ${services.orca.baseUrl:localhost:8083}
# front50:
# baseUrl: ${services.front50.baseUrl:localhost:8080}
# mort:
# baseUrl: ${services.mort.baseUrl:localhost:7002}
# kato:
# baseUrl: ${services.kato.baseUrl:localhost:7002}
# #optional services:
# echo:
# enabled: ${services.echo.enabled:true}
# baseUrl: ${services.echo.baseUrl:8089}
# flapjack:
# enabled: ${services.flapjack.enabled:false}
# igor:
# enabled: ${services.igor.enabled:false}
# baseUrl: ${services.igor.baseUrl:8088}
redis:
connection: ${services.redis.connection}

10
google/config/gce-kms.yml Normal file
Просмотреть файл

@ -0,0 +1,10 @@
server:
port: ${services.gce_kms.port:7909}
address: ${services.gce_kms.host:localhost}
credentials:
accounts:
- name: ${providers.google.primaryCredentials.name}
project: ${providers.google.primaryCredentials.project}
jsonPath: ${providers.google.primaryCredentials.jsonPath}

15
google/config/igor.yml Normal file
Просмотреть файл

@ -0,0 +1,15 @@
server:
port: ${services.igor.port:8088}
address: ${services.igor.host:localhost}
jenkins:
masters:
- name: ${services.jenkins.name}
address: ${services.jenkins.baseUrl}
username: ${services.jenkins.username}
password: ${services.jenkins.password}
# This is recursive
#services:
# echo:
# baseUrl: ${services.echo.baseUrl}

38
google/config/orca.yml Normal file
Просмотреть файл

@ -0,0 +1,38 @@
server:
port: ${services.orca.port:8083}
address: ${services.orca.host:localhost}
oort:
baseUrl: ${services.oort.baseUrl:localhost:7002}
front50:
baseUrl: ${services.front50.baseUrl:localhost:8080}
mort:
baseUrl: ${services.mort.baseUrl:localhost:7002}
kato:
baseUrl: ${services.kato.baseUrl:localhost:7002}
rush:
baseUrl: ${services.rush.baseUrl:localhost:8085}
bakery:
baseUrl: ${services.bakery.baseUrl:localhost:8087}
extractBuildDetails: ${services.bakery.extractBuildDetails:true}
propagateCloudProviderType: ${services.bakery.propagateCloudProviderType:true}
echo:
baseUrl: ${services.echo.baseUrl:8089}
igor:
baseUrl: ${services.igor.baseUrl:8088}
# TODO(duftler): Remove this once flex is conditionally-enabled in orca.
flex:
baseUrl: http://not-a-host
default:
bake:
account: default
securityGroups:
vpc:
securityGroups:
redis:
connection: ${services.redis.connection}

21
google/config/rosco.yml Normal file
Просмотреть файл

@ -0,0 +1,21 @@
server:
port: ${services.rosco.port:8087}
address: ${services.rosco.host:localhost}
redis:
host: ${services.redis.host:localhost}
aws:
enabled: ${providers.aws.enabled:false}
docker:
enabled: ${services.docker.enabled:false}
google:
enabled: ${providers.google.enabled:false}
gce:
bakeryDefaults:
project: ${providers.google.primaryCredentials.project}
rush:
credentials: ${services.rush.primaryAccount}

13
google/config/rush.yml Normal file
Просмотреть файл

@ -0,0 +1,13 @@
server:
port: ${services.rush.port:8085}
address: ${services.rush.host:localhost}
cassandra:
embedded: ${services.cassandra.embedded:false}
host: ${services.cassandra.host:localhost}
docker:
accounts:
- name: ${services.docker.primaryAccount.name}
url: ${services.docker.primaryAccount.url}
registry: ${services.docker.primaryAccount.registry}

Просмотреть файл

@ -0,0 +1,29 @@
providers:
google:
enabled: true
primaryCredentials:
name: my-account-name
project: ewiseblatt-spinnaker-0000
jsonPath: /root/.spinnaker/ManagedProjectCredentials.json
services:
redis:
host: 10.240.0.3
cassandra:
host: 10.240.0.3
jenkins:
host:
port:
username:
password;
docker:
host:
port:
primaryAccount:
name: ${providers.google.primaryCredentials.name}
rush:
primaryAccount: ${providers.google.primaryCredentials.name}

Просмотреть файл

@ -1,32 +1,32 @@
'use strict';
let gateHost = '$GATE_HOST:$GATE_PORT';
let gateHost = '${services.gate.host}:${services.gate.port}';
window.spinnakerSettings = {
gateUrl: `http://${gateHost}`,
bakeryDetailUrl: 'http://$BAKERY_HOST:$BAKERY_PORT/api/v1/global/logs/{{context.status.id}}?html=true',
gateUrl: `${services.gate.baseUrl}`,
bakeryDetailUrl: '${services.bakery.baseUrl}/api/v1/global/logs/{{context.status.id}}?html=true',
pollSchedule: 30000,
defaultTimeZone: 'America/New_York', // see http://momentjs.com/timezone/docs/#/data-utilities/
providers: {
gce: {
defaults: {
account: '$GOOGLE_PRIMARY_ACCOUNT_NAME',
region: '$GOOGLE_DEFAULT_REGION',
zone: '$GOOGLE_DEFAULT_ZONE',
account: '${providers.google.primaryCredentials.name}',
region: '${providers.google.defaultRegion}',
zone: '${providers.google.defaultZone}',
},
primaryAccounts: ['$GOOGLE_PRIMARY_ACCOUNT_NAME'],
challengeDestructiveActions: ['$GOOGLE_PRIMARY_ACCOUNT_NAME'],
primaryAccounts: ['${providers.google.primaryCredentials.name}'],
challengeDestructiveActions: ['${providers.google.primaryCredentials.name}'],
},
aws: {
defaults: {
account: '$AWS_PRIMARY_ACCOUNT_NAME',
region: '$AWS_DEFAULT_REGION'
account: '${providers.aws.primaryCredentials.name}',
region: '${providers.aws.defaultRegion}',
},
primaryAccounts: ['$AWS_PRIMARY_ACCOUNT_NAME'],
primaryAccounts: ['${providers.aws.primaryCredentials.name}]',
primaryRegions: ['eu-west-1', 'us-east-1', 'us-west-1', 'us-west-2'],
challengeDestructiveActions: ['$AWS_PRIMARY_ACCOUNT_NAME'],
challengeDestructiveActions: ['${providers.aws.primaryCredentials.name}'],
preferredZonesByAccount: {
$AWS_PRIMARY_ACCOUNT_NAME: {
${providers.aws.primaryCredentials.name}: {
'us-east-1': ['us-east-1a', 'us-east-1b', 'us-east-1d', 'us-east-1e'],
'us-west-1': ['us-west-1a', 'us-west-1b', 'us-west-1c'],
'us-west-2': ['us-west-2a', 'us-west-2b', 'us-west-2c'],

130
google/config/spinnaker.yml Normal file
Просмотреть файл

@ -0,0 +1,130 @@
global:
spinnaker:
environment: test
serviceProtocol: http
services:
clouddriver:
host: localhost
port: 7002
baseUrl: ${serviceProtocol}://${services.clouddriver.host}:${services.clouddriver.port}
echo:
enabled: true
host: localhost
port: 8089
baseUrl: ${serviceProtocol}://${services.echo.host}:${services.echo.port}
front50:
host: localhost
port: 8080
baseUrl: ${serviceProtocol}://${services.front50.host}:${services.front50.port}
gate:
host: localhost
port: 8084
baseUrl: ${serviceProtocol}://${services.gate.host}:${services.gate.port}
igor:
enabled: false
host: localhost
port: 8088
baseUrl: ${serviceProtocol}://${services.igor.host}:${services.igor.port}
kato:
host: ${services.clouddriver.host}
port: ${services.clouddriver.port}
baseUrl: ${services.clouddriver.baseUrl}
gce_kms:
host: localhost
port: 7909
baseUrl: ${serviceProtocol}://${services.gce_kms.host}:${services.gce_kms.port}
mort:
host: ${services.clouddriver.host}
port: ${services.clouddriver.port}
baseUrl: ${services.clouddriver.baseUrl}
orca:
host: localhost
port: 8083
baseUrl: ${serviceProtocol}://${services.orca.host}:${services.orca.port}
enabled: true
oort:
host: ${services.clouddriver.host}
port: ${services.clouddriver.port}
baseUrl: ${services.clouddriver.baseUrl}
rosco:
host: localhost
port: 8087
baseUrl: ${serviceProtocol}://${services.rosco.host}:${services.rosco.port}
rush:
host: localhost
port: 8085
baseUrl: ${serviceProtocol}://${services.rush.host}:${services.rush.port}
primaryAccount: # Expected in spinnaker-local.yml
bakery:
host: ${services.rosco.host}
port: ${services.rosco.port}
baseUrl: ${services.rosco.baseUrl}
extractBuildDetails: true
propagateCloudProviderType: true
docker:
enabled: false
host: # Expected in spinnaker-local.yaml
port: # Expected in spinnaker-local.yaml
baseUrl: http://${services.docker.host}:${services.docker.port}
primaryAccount:
- name: docker-name-not-set # Expected in spinnaker-local.yml
url: ${services.docker.baseUrl}
registry: ${services.dockerRegistry.baseUrl}
dockerRegistry:
host: localhost
port: 5000
baseUrl: http://${services.dockerRegistry.host}:${services.dockerRegistry.port}
jenkins:
host: # Expected in spinnaker-local.yml
port: # Expected in spinnaker-local.yml
username: # Expected in spinnaker-local.yml
password: # Expected in spinnaker-local.yml
baseUrl: http://${services.jenkins.host}:${services.jenkins.port}
redis:
host: localhost
port: 6379
connection: redis://${services.redis.host}:${services.redis.port}
cassandra:
host: localhost
port: 9042
embedded: false
cluster: CASS_SPINNAKER
providers:
google:
enabled: false
primaryCredentials:
name: my-account
project:
jsonPath:
credentials:
name: ${providers.google.primaryCredentials.name}
project: ${providers.google.primaryCredentials.project}
jsonPath: ${providers.google.primaryCredentials.jsonPath}
aws:
enabled: false
simpleDBEnabled: false
defaultSimpleDBDomain: CLOUD_APPLICATIONS
# aws_access_key:
# aws_secret_key:

Просмотреть файл

@ -88,7 +88,7 @@ def ensure_gcs_bucket(name, project=''):
project = match.group(1)
list_result = run_quick('gsutil list -p ' + project)
list_result = run_quick('gsutil list -p ' + project, echo=False)
if list_result.returncode:
error = ('Could not create Google Cloud Storage bucket'
'"{name}" in project "{project}":\n{error}'
@ -292,20 +292,43 @@ class Builder(object):
self.__options.cpu_ratio * multiprocessing.cpu_count()))
pool.map(self.__do_build, SUBSYSTEM_LIST)
processes = []
source_config_dir = self.__options.config_source
processes = []
# Copy global spinnaker config (and sample showing customization).
for yml in [ 'sample-spinnaker-local.yml', 'spinnaker.yml']:
source_config = os.path.join(source_config_dir, yml)
target_config = os.path.join(self.__release_dir, 'config', yml)
self.__config_list.append(yml)
processes.append(self.start_copy_file(source_config, target_config))
# Copy subsystem configuration files.
for subsys in SUBSYSTEM_LIST:
processes.append(self.start_copy_debian_target(subsys))
if subsys == 'deck':
source_config = os.path.join(source_config_dir, 'settings.js')
target_config = os.path.join(
self.__release_dir, 'config/deck_settings.js')
# For the time being this is the deprecated google/ variable config.
source_config = os.path.join(source_config_dir,
'deprecated/settings.js')
target_config = os.path.join(
self.__release_dir, 'config/deck_settings.js')
processes.append(self.start_copy_file(source_config, target_config))
# For the time being add a second variation with the new proposed
# standard config. Rename this later; avoid confusion for now.
source_config = os.path.join(source_config_dir, 'settings.js')
target_config = os.path.join(
self.__release_dir, 'config/new_settings.js')
processes.append(self.start_copy_file(source_config, target_config))
else:
yml = '{name}-local.yml'.format(name=subsys)
source_config = os.path.join(source_config_dir, yml)
for source_config in [
os.path.join(source_config_dir, subsys + '.yml'),
os.path.join(source_config_dir,
'deprecated', subsys + '-local.yml')]:
yml = os.path.basename(source_config)
target_config = os.path.join(self.__release_dir, 'config', yml)
self.__config_list.append(yml)
processes.append(self.start_copy_file(source_config, target_config))
processes.append(
self.start_copy_file(source_config, target_config))
print 'Waiting for package copying to finish....'
for p in processes:
@ -382,7 +405,7 @@ class Builder(object):
try:
self.start_copy_file(
os.path.join(source_dir, 'default_spinnaker_config.cfg'),
os.path.join(source_dir, 'deprecated/default_spinnaker_config.cfg'),
os.path.join(target_dir, 'default_spinnaker_config.cfg')).check_wait()
self.start_copy_file(

Просмотреть файл

@ -45,8 +45,10 @@ class DevInstallationParameters(configure_util.InstallationParameters):
SPINNAKER_INSTALL_DIR = os.path.abspath(
os.path.join(DEV_SCRIPT_DIR, '..'))
CONFIG_TEMPLATE_DIR = os.path.abspath(
CONFIG_MASTER_DIR = os.path.abspath(
os.path.join(DEV_SCRIPT_DIR, '../config'))
CONFIG_TEMPLATE_DIR = os.path.abspath(
os.path.join(DEV_SCRIPT_DIR, '../config/deprecated'))
UTILITY_SCRIPT_DIR = os.path.abspath(
os.path.join(DEV_SCRIPT_DIR, '../runtime'))

Просмотреть файл

@ -90,6 +90,7 @@ function replace_startup_script() {
function extract_spinnaker_config() {
local config="$CONFIG_DIR/spinnaker_config.cfg"
mkdir -p $(dirname $config)
touch $config
chmod 600 $config
if clear_metadata_to_file "spinnaker_config" $config; then
@ -114,6 +115,7 @@ function extract_spinnaker_config() {
function extract_spinnaker_credentials() {
local json_path="$CONFIG_DIR/ManagedProjectCredentials.json"
mkdir -p $(dirname $json_path)
if clear_metadata_to_file "managed_project_credentials" $json_path; then
# This is a workaround for difficulties using the Google Deployment Manager
# to express no value. We'll use the value "None". But we dont want

Просмотреть файл

@ -48,7 +48,7 @@ def get_config_dir(options):
def get_config_template_dir(options):
"""Returns the directory used to hold configuration templates.
"""Returns the directory used to hold [deprecated] configuration templates.
These templates are used as the basis when running the reconfigure script.
"""
@ -56,6 +56,14 @@ def get_config_template_dir(options):
or os.path.join(get_spinnaker_dir(options), 'config_templates'))
def get_config_master_dir(options):
"""Returns the directory used to hold the installation master config.
These are not intended to be overriden, but -local variants can be added.
"""
return (os.path.join(get_spinnaker_dir(options), 'config'))
def get_spinnaker_dir(options):
"""Returns the spinnaker installation directory."""
path = options.spinnaker_dir or '/opt/spinnaker'
@ -277,6 +285,7 @@ def install_spinnaker_packages(options, bucket):
print 'Installing Spinnaker components from {0}.'.format(bucket)
config_dir = get_config_dir(options)
master_dir = get_config_master_dir(options)
template_dir = get_config_template_dir(options)
spinnaker_dir = get_spinnaker_dir(options)
@ -286,15 +295,37 @@ def install_spinnaker_packages(options, bucket):
# Copy Configuration files
###########################
print 'Copying configuration files.'
safe_mkdir(config_dir)
safe_mkdir(template_dir)
safe_mkdir(master_dir)
# For now we are copying both the old configuration files
# and the new ones.
# The new ones are not yet fully working so we are keeping
# the old ones around. It's particularly messy because the two
# cohabitate the same directory in the bucket. We separate them
# out in the installation so that the old -local files arent
# intercepted (with precedence) when using the new files.
# The new files are not enabled by default.
for cfg in CONFIG_LIST:
# Copy everything into the [new] master directory.
# Then we'll move out all the old local files.
jobs.append(start_copy_file(options,
os.path.join(bucket, 'config', cfg),
config_dir))
jobs.append(start_copy_file(options,
os.path.join(bucket, 'config', cfg),
template_dir))
master_dir))
jobs.append(
start_copy_file(
options,
os.path.join(bucket, 'config/new_settings.js'),
os.path.join(bucket, master_dir + '/settings.js')))
check_wait_for_copy_complete(jobs)
jobs = []
# This will also move the new local sample, but dont
# worry about that since eventually the old stuff will go away
# and we wont need this mv.
safe_mkdir(template_dir)
run_quick('mv {master}/*-local.yml {template}'.format(
master=master_dir, template=template_dir))
jobs.append(
start_copy_file(options,

Просмотреть файл

@ -241,8 +241,12 @@ class InstallationParameters(object):
EXTERNAL_DEPENDENCY_SCRIPT_DIR: Path to directory containing maintainence
and utility scripts for managing dependencies outside spinnaker itself.
CONFIG_MASTER_DIR: Path to directory containing the master configuration
files for the release. These are intended to be read-only.
CONFIG_TEMPLATE_DIR: Path to directory containing the master configuration
template files used as the basis for reconfiguring an installation.
This is deprecated.
DECK_INSTALL_DIR: Path to directory where deck is installed, which is
typically different from the other spinnaker subsystems.
@ -260,6 +264,7 @@ class InstallationParameters(object):
EXTERNAL_DEPENDENCY_SCRIPT_DIR = '/opt/spinnaker/scripts'
CONFIG_TEMPLATE_DIR = SPINNAKER_INSTALL_DIR + '/config_templates'
CONFIG_MASTER_DIR = SPINNAKER_INSTALL_DIR + '/config'
DECK_INSTALL_DIR = '/var/www'
HACK_DECK_SETTINGS_FILENAME = 'deck_settings.js'