orch 0.0.1 → 0.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f67ca3214ddbc6302dde59fc294da08fd0dbd2b
4
- data.tar.gz: 572ce735ddf78eebbd1ace4c6d0b33a05892d37f
3
+ metadata.gz: 2505f295b3b9d24ec8cf03009803c9efa3afb0ef
4
+ data.tar.gz: 85462611db90a1799169b89ee601076d2bc0d7b3
5
5
  SHA512:
6
- metadata.gz: e890d242ed98f9986b2a2eced37f4798aa85baba10192ac3bc5baeae214611c84043fef017163388267fdd5f8807241eb2efda216e284849546acb205154af43
7
- data.tar.gz: 876005978425fba1769c54227c1473dddae4e83e5f210d98fcb5e5aa5e49f10d2d56454f31ff763841f7d83e0e771432405a81c1b15d45ee608f29e249fdeef1
6
+ metadata.gz: 496fb704230bc3d7410e46b15c4d7e67b3a604e0781461f38b505d862f0e5ac6694883deac23ee29c68510560de71049efd58c543fa1d94cb420a5b7b005fc8b
7
+ data.tar.gz: 6e5d5fcdbfbe50becbd7227dab42ce6b86932ed9b130127b923d7aff7ad9eb54d25092bd376820608e57f952d2515e851c49b5948b89e8e313f9a46e07a7ec3c
data/README.md CHANGED
@@ -14,9 +14,9 @@ Once the gem is installed, the command orch will be in your $PATH
14
14
 
15
15
  ## Usage
16
16
 
17
- Type "orch help" to get the list of commands and "orch help <command>" to get list of options for a given command.
17
+ Type "orch help" to get the list of commands and "orch help _command_" to get list of options for a given command.
18
18
 
19
- The general usecase is to run "orch deploy <job_spec>" to deploy a configuration to to Marathon or Chronos. A given job_spec can contain specifications for many jobs and for multiple environments. Various options to the deploy command gives control to exactly what is deployed.
19
+ The general usecase is to run "orch deploy _job_spec_" to deploy a configuration to to Marathon or Chronos. A given job_spec can contain specifications for many jobs and for multiple environments. Various options to the deploy command gives control to exactly what is deployed.
20
20
 
21
21
  ## Job spec format
22
22
 
@@ -33,7 +33,8 @@ The file ~/.orch/config.yaml would contain values for "chronos_url" and "maratho
33
33
 
34
34
  ## Examples
35
35
 
36
- TODO: show some examples
36
+ The examples directory contains various examples of the features of orch.
37
+ View [documentation there](examples/Examples.md) for more details.
37
38
 
38
39
  ## Contributing
39
40
 
@@ -0,0 +1,10 @@
1
+
2
+ # Examples
3
+
4
+ This directory contains several examples to show various orch features.
5
+
6
+ | File | Description
7
+ |-----------------------|------------------------------------------------------------------------|
8
+ | shimple-chronos.yml | A very simple chronos spec for a daily recurring job
9
+ | env-chronos.yml | Shows how to set up a chronos job for multiple deployment environments.
10
+ | simple-marathon.yml | A simple example of a Marathon job using orch
@@ -3,7 +3,7 @@ default_job: &DEFAULT_JOB
3
3
  kind: Chronos
4
4
  environment: override me
5
5
  cronos_spec: &DEFAULT_SPEC
6
- name: "ray-test-{{ENV}}"
6
+ name: "ray-test-{{DEPLOY_ENV}}"
7
7
  schedule: "R/2015-01-25T21:00/PT24H"
8
8
  scheduleTimeZone: "PST"
9
9
  owner: "rjohnson@yp.com"
@@ -17,30 +17,46 @@ default_job: &DEFAULT_JOB
17
17
  environmentVariables:
18
18
  -
19
19
  name: "LOG_LOCATION"
20
- value: "/var/{{ENV}}"
20
+ value: "/var/{{DEPLOY_ENV}}"
21
21
  forcePullImage: false
22
22
  command: "echo \"log here: $LOG_LOCATION\"; echo \"ENV: $DEPLOY_ENV\";sleep 10; echo bye"
23
23
 
24
24
  version: alpha1
25
- environments_var: DEPLOY_ENV
26
- environments:
27
- - dev
28
- - test
29
- - prod
25
+ environment_vars:
26
+ DEPLOY_ENV:
27
+ - dev
28
+ - test
29
+ - prod
30
+ COLO:
31
+ - west
32
+ - east
30
33
  applications:
31
34
  - <<: *DEFAULT_JOB
32
35
  environment: dev
36
+ DEPLOY_ENV: dev
37
+ COLO: east
33
38
  cronos_spec:
34
39
  <<: *DEFAULT_SPEC
35
40
  schedule: "R/2015-08-01T21:00/PT24H"
36
41
  forcePullImage: true
37
42
  - <<: *DEFAULT_JOB
38
43
  environment: test
44
+ DEPLOY_ENV: test
45
+ COLO: east
39
46
  cronos_spec:
40
47
  <<: *DEFAULT_SPEC
41
48
  schedule: "R/2015-08-01T21:10/PT24H"
42
49
  - <<: *DEFAULT_JOB
43
50
  environment: prod
51
+ DEPLOY_ENV: prod
52
+ COLO: east
53
+ cronos_spec:
54
+ <<: *DEFAULT_SPEC
55
+ schedule: "R/2015-08-01T21:30/PT24H"
56
+ - <<: *DEFAULT_JOB
57
+ environment: prod
58
+ DEPLOY_ENV: prod
59
+ COLO: west
44
60
  cronos_spec:
45
61
  <<: *DEFAULT_SPEC
46
62
  schedule: "R/2015-08-01T21:30/PT24H"
@@ -1,14 +1,14 @@
1
1
  version: alpha1
2
- environments_var: DEPLOY_ENV
3
- environments:
4
- - dev
5
- - test
6
- - prod
2
+ environment_vars:
3
+ DEPLOY_ENV:
4
+ - dev
5
+ - test
6
+ - prod
7
7
  applications:
8
8
  - kind: Marathon
9
- environment: dev
9
+ DEPLOY_ENV: dev
10
10
  marathon_spec:
11
- id: "ray-web-{{ENV}}"
11
+ id: "ray-web-{{DEPLOY_ENV}}"
12
12
  cpus: 0.1
13
13
  mem: 300
14
14
  instances: 10
data/lib/config.rb CHANGED
@@ -16,6 +16,22 @@ module Orch
16
16
  end
17
17
  end
18
18
 
19
+ def check_for_chronos_url
20
+ if (! @options.has_key?("chronos_url")) && (@APP_CONFIG.nil? || @APP_CONFIG["chronos_url"].nil?)
21
+ return false
22
+ else
23
+ return true
24
+ end
25
+ end
26
+
27
+ def check_for_marathon_url
28
+ if (! @options.has_key?("marathon_url")) && (@APP_CONFIG.nil? || @APP_CONFIG["marathon_url"].nil?)
29
+ return false
30
+ else
31
+ return true
32
+ end
33
+ end
34
+
19
35
  def chronos_url
20
36
  if @options.has_key?("chronos_url")
21
37
  # If passed in on command line override what is in config file
data/lib/deploy.rb CHANGED
@@ -36,6 +36,11 @@ module Orch
36
36
  end
37
37
 
38
38
  def verify_chronos(json_payload)
39
+ if @config.check_for_chronos_url == false
40
+ puts "no chronos_url - can not verify with server"
41
+ return
42
+ end
43
+
39
44
  spec = Hashie::Mash.new(JSON.parse(json_payload))
40
45
 
41
46
  uri = URI(@config.chronos_url)
@@ -79,6 +84,7 @@ module Orch
79
84
  end
80
85
  next
81
86
  end
87
+ # TODO: not sure how to compare arrays
82
88
  specVal = spec[key]
83
89
  jobVal = job[key]
84
90
  if spec[key].to_s.numeric?
@@ -89,7 +95,7 @@ module Orch
89
95
  jobVal = job[key]
90
96
  end
91
97
  if specVal != jobVal
92
- puts "#{key}= spec:#{spec[key]}, server:#{job[key]}"
98
+ puts "#{key}= spec:#{specVal}, server:#{jobVal}"
93
99
  foundDiff = true
94
100
  end
95
101
  end
@@ -101,9 +107,8 @@ module Orch
101
107
  uri = URI(@config.marathon_url)
102
108
  json_headers = {"Content-Type" => "application/json",
103
109
  "Accept" => "application/json"}
104
-
105
- # curl -L -H 'Content-Type: application/json' -X POST -d @$schedule_file $CHRONOS_URL/scheduler/iso8601
106
110
  puts uri
111
+
107
112
  http = Net::HTTP.new(uri.host, uri.port)
108
113
  response = http.put("/v2/apps/#{json_payload["id"]}", json_payload, json_headers)
109
114
 
@@ -117,5 +122,38 @@ module Orch
117
122
 
118
123
  return response
119
124
  end
125
+
126
+ def verify_marathon(json_payload)
127
+ if @config.check_for_marathon_url == false
128
+ puts "no marathon_url - can not verify with server"
129
+ return
130
+ end
131
+
132
+ spec = Hashie::Mash.new(JSON.parse(json_payload))
133
+
134
+ uri = URI(@config.marathon_url)
135
+ json_headers = {"Content-Type" => "application/json",
136
+ "Accept" => "application/json"}
137
+
138
+ http = Net::HTTP.new(uri.host, uri.port)
139
+ response = http.get("/v2/apps/#{spec.id}", json_headers)
140
+
141
+ # puts "Response #{response.code} #{response.message}: #{response.body}"
142
+
143
+ if response.code == 404.to_s
144
+ puts "job: #{spec.id} - is not deployed"
145
+ return
146
+ end
147
+
148
+ if response.code == 200.to_s
149
+ job = Hashie::Mash.new(JSON.parse(response.body))
150
+ foundDiffs = find_diffs(spec, job.app)
151
+ end
152
+
153
+ # TODO: handle error codes
154
+
155
+ return response
156
+ end
157
+
120
158
  end
121
159
  end
data/lib/orch/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Orch
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/orch.rb CHANGED
@@ -27,14 +27,16 @@ module Orch
27
27
  config.setup_config(marathon_url, chronos_url)
28
28
  end
29
29
 
30
- option :deploy_type, :default => 'all',
31
- :desc => 'chronos, marathon, all'
32
- option :env_type, :default => 'all',
33
- :desc => 'a valid environment defined in your config or all to deploy to all environments'
30
+ option :deploy_kind, :default => 'all',
31
+ :desc => 'deploys only the given application kind: chronos, marathon, all'
32
+ option :deploy_env, :default => 'all',
33
+ :desc => 'ENV_VAR=VALUE deploys only if an environment_var matches the given value'
34
34
  option :subst,
35
35
  :desc => 'KEY=VALUE substitute KEY with VALUE globaly in your config'
36
36
  option :show_json, :default => false,
37
37
  :desc => 'show the json result that would be sent to Chronos or Marathon'
38
+ option :server_verify, :default => true,
39
+ :desc => 'verify the configuration against the server'
38
40
  desc 'verify PATH', 'Checks basic syntax and does not deploy'
39
41
  def verify(file_name)
40
42
  parser = Orch::Parse.new(file_name, options)
@@ -42,25 +44,28 @@ module Orch
42
44
  puts "Number of configs found: #{result.length}"
43
45
  deploy = Orch::Deploy.new(options)
44
46
  result.each do |app|
45
- if parser.hasEnvironments
46
- puts "Name: #{app[:name]}, Type: #{app[:type]}, Would deploy: #{app[:deploy]}, Environment: #{app[:environment]}"
47
- else
48
- puts "Name: #{app[:name]}, Type: #{app[:type]}, Would deploy: #{app[:deploy]}"
47
+ printf "Name: %s, Type: %s, Deploy?: %s", app[:name], app[:type], app[:deploy]
48
+ app[:env_vars].each do |key, value|
49
+ printf ", %s: %s", key, value
49
50
  end
51
+ printf "\n"
50
52
  if options[:show_json]
51
53
  pretty = JSON.pretty_generate(app[:json])
52
54
  puts "JSON: #{pretty}"
53
55
  end
54
- if app[:type] == "Chronos"
56
+ if (app[:type] == "Chronos") && (options[:server_verify] == true)
55
57
  deploy.verify_chronos(app[:json].to_json)
56
58
  end
59
+ if (app[:type] == "Marathon") && (options[:server_verify] == true)
60
+ deploy.verify_marathon(app[:json].to_json)
61
+ end
57
62
  end
58
63
  end
59
64
 
60
- option :deploy_type, :default => 'all',
61
- :desc => 'chronos, marathon, all'
62
- option :env_type, :default => 'all',
63
- :desc => 'a valid environment defined in your config or all to deploy to all environments'
65
+ option :deploy_kind, :default => 'all',
66
+ :desc => 'deploys only the given application kind: chronos, marathon, all'
67
+ option :deploy_env, :default => 'all',
68
+ :desc => 'ENV_VAR=VALUE deploys only if an environment_var matches the given value'
64
69
  option :chronos_url,
65
70
  :desc => 'url to chronos master'
66
71
  option :marathon_url,
data/lib/parse.rb CHANGED
@@ -3,7 +3,6 @@ require 'json'
3
3
 
4
4
  module Orch
5
5
  class Parse
6
- attr_reader :hasEnvironments
7
6
 
8
7
  def initialize(path, options)
9
8
  if ! File.file?(path)
@@ -11,7 +10,12 @@ module Orch
11
10
  exit 1
12
11
  end
13
12
  # TODO: try resecue for any syntax issues in yaml file
14
- yaml = ::YAML.load_file(path)
13
+ begin
14
+ yaml = ::YAML.load_file(path)
15
+ rescue Psych::SyntaxError => e
16
+ puts "error parsing yaml file #{e}"
17
+ exit 1
18
+ end
15
19
  #puts yaml.to_json
16
20
 
17
21
  @options = options
@@ -35,19 +39,8 @@ module Orch
35
39
  exit 1
36
40
  end
37
41
 
38
- # Does this config support environments
39
- @hasEnvironments = false
40
- defined_environments = {}
41
- if (! spec.environments.nil?)
42
- @hasEnvironments = true
43
- spec.environments.each do |e|
44
- defined_environments[e] = e
45
- end
46
- end
47
-
48
- if (! spec.environments_var.nil?)
49
- @environments_var = spec.environments_var
50
- end
42
+ # Check for vault vars
43
+ env_var_values = parse_vault_vars(@spec)
51
44
 
52
45
  if spec.applications.nil?
53
46
  puts "required section applications: must have at least one application defined"
@@ -58,40 +51,30 @@ module Orch
58
51
  spec.applications.each do |app|
59
52
  # Check for valid kind paramter
60
53
  if app.kind.nil?
61
- puts "required field kind was not found"
54
+ puts "required field 'kind:' was not found"
62
55
  exit 1
63
56
  end
64
57
 
65
-
66
58
  if !(app.kind == "Chronos" || app.kind == "Marathon")
67
59
  puts "unsupported kind specified: #{app.kind} - must be: Chronos | Marathon"
68
60
  exit 1
69
61
  end
70
62
 
71
- if @hasEnvironments
72
- if !defined_environments.has_key?(app.environment)
73
- puts "environment \"#{app.environment}\" not defined in environments"
74
- exit 1
75
- end
76
- end
63
+ # Generate any environment variables that need to be merged in
64
+ spec_env_vars = parse_env_vars(app)
65
+ env_var_values = env_var_values.merge(spec_env_vars)
77
66
 
78
67
  if (app.kind == "Chronos")
79
- chronos_spec = parse_chronos(app)
68
+ chronos_spec = parse_chronos(app, env_var_values)
80
69
 
81
- result = {:name => chronos_spec["name"], :type => app.kind, :deploy => should_deploy?(app), :json => chronos_spec}
82
- if @hasEnvironments
83
- result[:environment] = app.environment
84
- end
70
+ result = {:name => chronos_spec["name"], :type => app.kind, :deploy => should_deploy?(app), :env_vars => env_var_values, :json => chronos_spec}
85
71
  results << result
86
72
  end
87
73
 
88
74
  if (app.kind == "Marathon")
89
- marathon_spec = parse_marathon(app)
75
+ marathon_spec = parse_marathon(app, env_var_values)
90
76
 
91
- result = {:name => marathon_spec["id"], :type => app.kind, :deploy => should_deploy?(app), :json => marathon_spec}
92
- if @hasEnvironments
93
- result[:environment] = app.environment
94
- end
77
+ result = {:name => marathon_spec["id"], :type => app.kind, :deploy => should_deploy?(app), :env_vars => env_var_values, :json => marathon_spec}
95
78
  results << result
96
79
  end
97
80
  end
@@ -99,31 +82,46 @@ module Orch
99
82
  return results
100
83
  end
101
84
 
102
- def parse_chronos(app)
103
- # TODO: check if it exists
104
- cronos_spec = app.cronos_spec
105
-
106
- # This adds environment vaiables to the spec that conform to our docker-wrapper security hack
107
- if ! app.vault.nil?
108
- # TODO: check that an environment was defined
109
- if (! @hasEnvironments) || app.environment.nil?
110
- puts "the vault feature requires an environment to be set"
111
- exit 1
85
+ def parse_env_vars(app)
86
+ result = {}
87
+ if (! @spec.environment_vars.nil?)
88
+ @spec.environment_vars.each do |key, value|
89
+ if app[key].nil?
90
+ puts "environments_var #{key} specified - but not included in app"
91
+ # TODO: would be nice to put the app name...
92
+ exit 1
93
+ end
94
+ if ! @spec.environment_vars[key].include? app[key]
95
+ puts "#{key} value \"#{app[key]}\" not in #{@spec.environment_vars[key].to_s}"
96
+ exit 1
97
+ end
98
+ result[key] = app[key]
112
99
  end
100
+ end
113
101
 
102
+ return result
103
+ end
104
+
105
+ def parse_vault_vars(spec)
106
+ result = {}
107
+ if ! spec.vault.nil?
114
108
  count = 1
115
- cronos_spec.environmentVariables ||= []
116
- app.vault.each do |vault_key|
117
- # Add an environment
118
- pair = {"name" => "VAULT_KEY_#{count}", "value" => vault_key}
109
+ spec.vault.each do |vault_key|
110
+ result["VAULT_KEY_#{count}"] = vault_key
119
111
  count += 1
120
- cronos_spec.environmentVariables << pair
121
112
  end
122
113
  end
114
+ return result
115
+ end
116
+
117
+ def parse_chronos(app, env_var_values)
118
+ # TODO: check if it exists
119
+ cronos_spec = app.cronos_spec
123
120
 
124
- if (! @environments_var.nil?)
125
- pair = {"name" => @environments_var, "value" => app.environment}
126
- cronos_spec.environmentVariables << pair
121
+ # Augment any spec environment variables with meta values
122
+ env_var_values.each do |key, value|
123
+ pair = {"name" => key, "value" => value}
124
+ cronos_spec.environmentVariables << pair
127
125
  end
128
126
 
129
127
  # Do subst processing
@@ -133,29 +131,13 @@ module Orch
133
131
  return cronos_spec
134
132
  end
135
133
 
136
- def parse_marathon(app)
134
+ def parse_marathon(app, env_var_values)
137
135
  # TODO: check if it exists
138
136
  marathon_spec = app.marathon_spec
139
137
 
140
- # This adds environment vaiables to the spec that conform to our docker-wrapper security hack
141
- if ! app.vault.nil?
142
- # TODO: check that an environment was defined
143
- if (! @hasEnvironments) || app.environment.nil?
144
- puts "the vault feature requires an environment to be set"
145
- exit 1
146
- end
147
-
148
- count = 1
149
- marathon_spec.env ||= {}
150
- app.vault.each do |vault_key|
151
- # Add an environment
152
- marathon_spec.env["VAULT_KEY_#{count}"] = vault_key
153
- count += 1
154
- end
155
- end
156
-
157
- if (! @environments_var.nil?)
158
- marathon_spec.env[@environments_var] = app.environment
138
+ # Augment any spec environment variables with meta values
139
+ env_var_values.each do |key, value|
140
+ marathon_spec.env[key] = value
159
141
  end
160
142
 
161
143
  spec_str = do_subst(marathon_spec, app)
@@ -166,15 +148,25 @@ module Orch
166
148
 
167
149
  def should_deploy?(app)
168
150
  result = true
169
- if (app.kind == "Marathon") && @options[:deploy_type] == 'chronos'
151
+ if (app.kind == "Marathon") && @options[:deploy_kind] == 'chronos'
170
152
  result = false
171
153
  end
172
- if (app.kind == "Chronos") && @options[:deploy_type] == 'marathon'
154
+ if (app.kind == "Chronos") && @options[:deploy_kind] == 'marathon'
173
155
  result = false
174
156
  end
175
- if @options[:env_type] != 'all'
176
- if @options[:env_type] != app.environment
177
- result = false
157
+
158
+ if @options[:deploy_env] != 'all'
159
+ @options[:deploy_env].split(",").each do |x|
160
+ pair = x.split("=")
161
+ envVar = pair[0]
162
+ envVal = pair[1]
163
+ if app[envVar].nil?
164
+ puts "environment var of '#{envVar}' not found in app"
165
+ exit 1
166
+ end
167
+ if app[envVar] != envVal
168
+ result = false
169
+ end
178
170
  end
179
171
  end
180
172
 
@@ -182,9 +174,16 @@ module Orch
182
174
  end
183
175
 
184
176
  def do_subst(spec, app)
185
- # {{ENV}} is a special value
186
- spec_str = spec.to_json.to_s.gsub(/{{ENV}}/, app.environment)
177
+ spec_str = spec.to_json.to_s
178
+
179
+ # Subst any of the environment_vars values
180
+ if (! @spec.environment_vars.nil?)
181
+ @spec.environment_vars.each do |key, value|
182
+ spec_str = spec_str.gsub(/{{#{key}}}/, app[key])
183
+ end
184
+ end
187
185
 
186
+ # Subst any values that were passed in via command line
188
187
  if ! @options[:subst].nil?
189
188
  @options[:subst].split(",").each do |x|
190
189
  pair = x.split("=")
@@ -200,8 +199,8 @@ module Orch
200
199
  return
201
200
  end
202
201
 
203
- if ! ['chronos', 'marathon', 'all'].include?(@options[:deploy_type])
204
- puts "value of --deploy-type was #{@options[:deploy_type]}, must be chronos, marathon or all"
202
+ if ! ['chronos', 'marathon', 'all'].include?(@options[:deploy_kind])
203
+ puts "value of --deploy-type was #{@options[:deploy_kind]}, must be chronos, marathon or all"
205
204
  exit 1
206
205
  end
207
206
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ray Johnson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-21 00:00:00.000000000 Z
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,7 @@ files:
80
80
  - README.md
81
81
  - Rakefile
82
82
  - bin/orch
83
+ - examples/Examples.md
83
84
  - examples/env-chronos.yml
84
85
  - examples/simple-chronos.yml
85
86
  - examples/simple-marathon.yml