orch 0.0.2 → 0.0.3

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: 2505f295b3b9d24ec8cf03009803c9efa3afb0ef
4
- data.tar.gz: 85462611db90a1799169b89ee601076d2bc0d7b3
3
+ metadata.gz: 4fc678adcfcacd47d4c3424fffae37cfba36f7f1
4
+ data.tar.gz: deba3fb34b70a3b486c400b71ff395b869fa0a9a
5
5
  SHA512:
6
- metadata.gz: 496fb704230bc3d7410e46b15c4d7e67b3a604e0781461f38b505d862f0e5ac6694883deac23ee29c68510560de71049efd58c543fa1d94cb420a5b7b005fc8b
7
- data.tar.gz: 6e5d5fcdbfbe50becbd7227dab42ce6b86932ed9b130127b923d7aff7ad9eb54d25092bd376820608e57f952d2515e851c49b5948b89e8e313f9a46e07a7ec3c
6
+ metadata.gz: bf766eea2fd37950ac0fa9fcbe2528e4b51748570f0ae104cc73796bc667403d994e64e310c964fd882bfb2adca49aaaaefe4e412e39df7bf2c7ddcf08ef6b95
7
+ data.tar.gz: 5f1e9ce4837fb1a4ca65cefc4fc12005ffb0d6f94d98a3f58c45b059b972725120310374df0cc02cc7bcce63f447e7e1cfe06e5938bc52257c6d55aa8bccca08
data/README.md CHANGED
@@ -20,7 +20,133 @@ The general usecase is to run "orch deploy _job_spec_" to deploy a configuration
20
20
 
21
21
  ## Job spec format
22
22
 
23
- TODO: describe the file
23
+ The orch Yaml format is really a wrapper for multiple Marathon or Chronos job descriptions. The format is based on yaml. To get a basic understanding of Yaml files check out: http://www.yaml.org/start.html
24
+
25
+ The basic orch syntax is as follows:
26
+ ```
27
+ version: alpha1
28
+ applications:
29
+ - kind: Chronos
30
+ chronos_spec:
31
+ ...
32
+ ```
33
+
34
+ The **version:** field must currently always be alpha1. Eventually, this tool may need to support a revised format and this can be used to support multiple versions.
35
+
36
+ The **applications:** field contains an array of Chronos or Marathon configurations. Each array must have a **kind:** field with a value of _Chronos_ or _Marathon_ which simply tells orch what type of config this is. Depending on the value of **kind:** a field of **chronos_spec:** or **marathon_spec:** is also required.
37
+
38
+ The values of **chronos_spec:** should simply be the yaml equivelent of the chronos json messages. You can find documentation for chronos json format here: https://mesos.github.io/chronos/docs/api.html
39
+
40
+
41
+ Likewise, the values of **marathon_spec:** should simply be the yaml equivelent of the marathon json messages. You can find documentation for marathon json format here: https://mesosphere.github.io/marathon/docs/rest-api.html
42
+
43
+ So far all we have is a different way to specify a job. The real power of orch will come from using meta data to act on these configs in more interesting ways...
44
+
45
+ ### Deployment vars
46
+
47
+ The **deploy_vars:** field allows you to define some values that can be used to drive deployment of the same config for multiple uses. Often it is useful to have *dev*, *test* & *prod* environments for our application. Generally we want to use the same specification for all environments but we need a way to differentiate them and allow the app at run time to know what environment it is running in.
48
+
49
+ Let's start with an example:
50
+ ```
51
+ deploy_vars:
52
+ DEPLOY_ENV:
53
+ - dev
54
+ - test
55
+ - prod
56
+ ```
57
+ This example will define an environment variable named **DEPLOY_ENV**. (You can name it whatever you want.) We are defining it here to have values of *dev*, *test*, and *prod*.
58
+
59
+ You then would need to specify that variable in your application sections like this:
60
+ ```
61
+ version: alpha1
62
+ deploy_vars:
63
+ DEPLOY_ENV:
64
+ - dev
65
+ - test
66
+ - prod
67
+ applications:
68
+ - kind: Chronos
69
+ DEPLOY_ENV: dev
70
+ chronos_spec:
71
+ name: "myapp-{{DEPLOY_ENV}}"
72
+ ...
73
+ - kind: Chronos
74
+ DEPLOY_ENV: prod
75
+ chronos_spec:
76
+ name: "myapp-{{DEPLOY_ENV}}"
77
+ ...
78
+ ```
79
+
80
+ When orch runs it will insert the environment variable into the *env* or *environmentVariables* sections of your spec. However, you can also use the **--deploy-env** command line option to tell orch to only deploy a paticular environment. You can also use the substitution feature to use the value of your environment varaible in other parts of the config like name. *(e.g. `name: "myapp-{{DEPLOY_ENV}}"` would substitute to `name: "myapp-dev"` for the dev environment)*
81
+
82
+ ### Alternative way to set environment variables
83
+
84
+ Chronos and Marathon use different syntx to specify environment variables. Also, you may want to specify certain variables consistently across several applications in your orch spec. The **env:** field provides a way to do that with a nice clean syntax.
85
+
86
+
87
+ The env field could be used at the top level of the spec to be used across all applications in the spec:
88
+ ```
89
+ version: alpha1
90
+ env:
91
+ GOOGLE_URL: http://www.google.com
92
+ YP_URL: http://www.yp.com
93
+ applications:
94
+ ...
95
+ ```
96
+
97
+ Or you can also specify it at the application level as an alternative syntax to specifying it in the *marathon_spec:* or *chronos_spec:* sections - like this:
98
+ ```
99
+ version: alpha1
100
+ env:
101
+ GOOGLE_URL: http://www.google.com
102
+ YP_URL: http://www.yp.com
103
+ applications:
104
+ - kind: Marathon
105
+ env:
106
+ GOOGLE_URL: http://www.google.com
107
+ YP_URL: http://www.yp.com
108
+ marathon_spec:
109
+ ...
110
+ ```
111
+
112
+ Lower level definitions of an env var will supeceed higher level version. That is if you specify an env value in the *marathon_spec* or *chronos_spec* level it will override anything set at the *app* or *orch* level.
113
+ ### Yaml anchors and aliases
114
+
115
+ The nice thing about using Yaml as the spec format is the ability to use Yaml's anchors (&) and alias (*) syntax. This allows you to specify sections of your configuration that can be reused across multiple jobs. Typically if you have a job for multiple deployment environments you what them all to have the same spec - except perhaps override one or two things. (Like an envionment value or the docker image.)
116
+
117
+ We will refer you to other documentation on the internet on how to use Yaml anchors and aliases. However, you can take a look at a couple of the [provided examples](examples/Examples.md) to see how you might use Yaml to its fullest.
118
+
119
+ ### Substition
120
+
121
+ A primary use case of **orch** is to use the tool from within a Makefile. You may want to subsitite parts of you configuration from vairables in your Makefile. In the *Deployment vars* section we showed you how you can use deployment vars as substitution values in other parts of the configuration.
122
+
123
+ **Orch** also provides the *--subst* option to provide a way to pass additional substitution vars when running your configuration. A common use case might be to pass in the tag for a Docker image that is managed by your Makefile. Here is an example:
124
+ ```
125
+ todo: provide an example
126
+ ```
127
+
128
+ TODO: finish this section
129
+
130
+ ### Bamboo
131
+
132
+ [Bamboo](https://github.com/QubitProducts/bamboo) is a tool that creates an HAProxy for providing an easier way to get to a farm of web servers hosted by Marathon. You define the Marathon id of the application you want to load balance and an acl to tell HAProxy what url to direct to your marathon application.
133
+
134
+ Orch provides a way to also configure your Bamboo server from your orch config. Here is an example:
135
+ ```
136
+ version: alpha1
137
+ applications:
138
+ - kind: Marathon
139
+ marathon_spec:
140
+ ...
141
+ bamboo_spec:
142
+ acl: "hdr(host) -i test-web.int.yp.com"
143
+ ```
144
+
145
+ An additional *bamboo_spec:* field is added to the Marathon application at the same level as the *marathon_spec:* field. The *bamboo_spec:* field contains one field called *acl:*. The simply has a acl rule for HAProxy. See Bamboo documentation for more details.
146
+
147
+ Note: you will also need to set the **bamboo_url:** feild of your configutation.
148
+
149
+ ### TODO: section on vault
24
150
 
25
151
  ## Configuration Options
26
152
 
data/examples/Examples.md CHANGED
@@ -5,6 +5,8 @@ This directory contains several examples to show various orch features.
5
5
 
6
6
  | File | Description
7
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.
8
+ | shimple-chronos.yml | A very simple chronos spec for a daily recurring job. It also has a simple example of a dependant job.
9
+ | env-chronos.yml | Shows how to set up a chronos job for multiple deployment environments. It also gives a good example of how to use Yaml anchors, the use of multiple deploy_vars: fields, and how to use deploy_vars fields in substitutions.
10
10
  | simple-marathon.yml | A simple example of a Marathon job using orch
11
+ | env-marathon.yml | A more complex marathon example showing multiple deployment environments.
12
+ | bamboo-ex.yml | Example of using Marathon with Bamboo.
@@ -0,0 +1,47 @@
1
+ default_job: &DEFAULT_JOB
2
+ kind: Marathon
3
+ DEPLOY_ENV: dev
4
+ bamboo_spec:
5
+ acl: "hdr(host) -i test-web-{{DEPLOY_ENV}}.ypec.int.yp.com"
6
+ marathon_spec: &DEFAULT_SPEC
7
+ id: "test-bamboo-{{DEPLOY_ENV}}"
8
+ cpus: 0.1
9
+ mem: 300
10
+ instances: 3
11
+ container: &DEFAULT_CONTAINER
12
+ type: "DOCKER"
13
+ docker: &DEFAULT_DOCKER
14
+ image: "nginx"
15
+ network: "BRIDGE"
16
+ portMappings:
17
+ -
18
+ containerPort: 80
19
+ hostPort: 0
20
+ protocol: "tcp"
21
+ forcePullImage: false
22
+
23
+ version: alpha1
24
+ deploy_vars:
25
+ DEPLOY_ENV:
26
+ - dev
27
+ - test
28
+ - prod
29
+ env:
30
+ DEBUG_FLAG: true
31
+ applications:
32
+ - <<: *DEFAULT_JOB
33
+ DEPLOY_ENV: dev
34
+ marathon_spec:
35
+ <<: *DEFAULT_SPEC
36
+ container:
37
+ <<: *DEFAULT_CONTAINER
38
+ docker:
39
+ <<: *DEFAULT_DOCKER
40
+ forcePullImage: true
41
+ - <<: *DEFAULT_JOB
42
+ DEPLOY_ENV: test
43
+ - <<: *DEFAULT_JOB
44
+ DEPLOY_ENV: prod
45
+ env:
46
+ DEBUG_FLAG: false
47
+
@@ -1,9 +1,8 @@
1
1
 
2
2
  default_job: &DEFAULT_JOB
3
3
  kind: Chronos
4
- environment: override me
5
- cronos_spec: &DEFAULT_SPEC
6
- name: "ray-test-{{DEPLOY_ENV}}"
4
+ chronos_spec: &DEFAULT_SPEC
5
+ name: "ray-test-{{DEPLOY_ENV}}-{{COLO}}"
7
6
  schedule: "R/2015-01-25T21:00/PT24H"
8
7
  scheduleTimeZone: "PST"
9
8
  owner: "rjohnson@yp.com"
@@ -18,11 +17,10 @@ default_job: &DEFAULT_JOB
18
17
  -
19
18
  name: "LOG_LOCATION"
20
19
  value: "/var/{{DEPLOY_ENV}}"
21
- forcePullImage: false
22
20
  command: "echo \"log here: $LOG_LOCATION\"; echo \"ENV: $DEPLOY_ENV\";sleep 10; echo bye"
23
21
 
24
22
  version: alpha1
25
- environment_vars:
23
+ deploy_vars:
26
24
  DEPLOY_ENV:
27
25
  - dev
28
26
  - test
@@ -32,31 +30,26 @@ environment_vars:
32
30
  - east
33
31
  applications:
34
32
  - <<: *DEFAULT_JOB
35
- environment: dev
36
33
  DEPLOY_ENV: dev
37
34
  COLO: east
38
- cronos_spec:
35
+ chronos_spec:
39
36
  <<: *DEFAULT_SPEC
40
37
  schedule: "R/2015-08-01T21:00/PT24H"
41
- forcePullImage: true
42
38
  - <<: *DEFAULT_JOB
43
- environment: test
44
39
  DEPLOY_ENV: test
45
40
  COLO: east
46
- cronos_spec:
41
+ chronos_spec:
47
42
  <<: *DEFAULT_SPEC
48
43
  schedule: "R/2015-08-01T21:10/PT24H"
49
44
  - <<: *DEFAULT_JOB
50
- environment: prod
51
45
  DEPLOY_ENV: prod
52
46
  COLO: east
53
- cronos_spec:
47
+ chronos_spec:
54
48
  <<: *DEFAULT_SPEC
55
49
  schedule: "R/2015-08-01T21:30/PT24H"
56
50
  - <<: *DEFAULT_JOB
57
- environment: prod
58
51
  DEPLOY_ENV: prod
59
52
  COLO: west
60
- cronos_spec:
53
+ chronos_spec:
61
54
  <<: *DEFAULT_SPEC
62
55
  schedule: "R/2015-08-01T21:30/PT24H"
@@ -0,0 +1,44 @@
1
+ default_job: &DEFAULT_JOB
2
+ kind: Marathon
3
+ DEPLOY_ENV: dev
4
+ marathon_spec: &DEFAULT_SPEC
5
+ id: "test-web-{{DEPLOY_ENV}}"
6
+ cpus: 0.1
7
+ mem: 300
8
+ instances: 3
9
+ container: &DEFAULT_CONTAINER
10
+ type: "DOCKER"
11
+ docker: &DEFAULT_DOCKER
12
+ image: "nginx"
13
+ network: "BRIDGE"
14
+ portMappings:
15
+ -
16
+ containerPort: 80
17
+ hostPort: 0
18
+ protocol: "tcp"
19
+ forcePullImage: false
20
+
21
+ version: alpha1
22
+ deploy_vars:
23
+ DEPLOY_ENV:
24
+ - dev
25
+ - test
26
+ - prod
27
+ env:
28
+ DEBUG_FLAG: true
29
+ applications:
30
+ - <<: *DEFAULT_JOB
31
+ DEPLOY_ENV: dev
32
+ marathon_spec:
33
+ <<: *DEFAULT_SPEC
34
+ container:
35
+ <<: *DEFAULT_CONTAINER
36
+ docker:
37
+ <<: *DEFAULT_DOCKER
38
+ forcePullImage: true
39
+ - <<: *DEFAULT_JOB
40
+ DEPLOY_ENV: test
41
+ - <<: *DEFAULT_JOB
42
+ DEPLOY_ENV: prod
43
+ env:
44
+ DEBUG_FLAG: false
@@ -1,9 +1,9 @@
1
1
  version: alpha1
2
2
  applications:
3
3
  - kind: Chronos
4
- cronos_spec:
5
- name: "ray-test"
6
- schedule: "R/2015-01-25T21:00/PT24H"
4
+ chronos_spec:
5
+ name: "orch-test-schedule"
6
+ schedule: "R/2015-01-25T21:00/PT03H"
7
7
  scheduleTimeZone: "PST"
8
8
  owner: "rjohnson@yp.com"
9
9
  container:
@@ -15,3 +15,19 @@ applications:
15
15
  uris: []
16
16
  forcePullImage: true
17
17
  command: "echo hello; sleep 10; echo bye"
18
+ - kind: Chronos
19
+ chronos_spec:
20
+ name: "orch-test-dependant-schedule"
21
+ parents:
22
+ - orch-test-schedule
23
+ scheduleTimeZone: "PST"
24
+ owner: "rjohnson@yp.com"
25
+ container:
26
+ type: "DOCKER"
27
+ image: "busybox"
28
+ network: "BRIDGE"
29
+ cpus: "0.5"
30
+ mem: "512"
31
+ uris: []
32
+ forcePullImage: true
33
+ command: "echo run-dependant-job; sleep 10; echo bye"
@@ -1,17 +1,12 @@
1
1
  version: alpha1
2
- environment_vars:
3
- DEPLOY_ENV:
4
- - dev
5
- - test
6
- - prod
7
2
  applications:
8
3
  - kind: Marathon
9
4
  DEPLOY_ENV: dev
10
5
  marathon_spec:
11
- id: "ray-web-{{DEPLOY_ENV}}"
6
+ id: "test-web-app"
12
7
  cpus: 0.1
13
8
  mem: 300
14
- instances: 10
9
+ instances: 2
15
10
  env:
16
11
  FOO: "bar"
17
12
  container:
@@ -24,5 +19,4 @@ applications:
24
19
  containerPort: 80
25
20
  hostPort: 0
26
21
  protocol: "tcp"
27
- forcePullImage: true
28
22
 
data/lib/bamboo.rb ADDED
@@ -0,0 +1,112 @@
1
+ # Chronos interface object
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'uri'
5
+
6
+ require 'config'
7
+
8
+ class String
9
+ def numeric?
10
+ Float(self) != nil rescue false
11
+ end
12
+ end
13
+
14
+ module Orch
15
+ class Bamboo
16
+ def initialize(options)
17
+ @config = Orch::Config.new(options)
18
+ end
19
+
20
+ def deploy(app_id, bamboo_spec)
21
+ uri = URI(@config.bamboo_url)
22
+ json_headers = {"Content-Type" => "application/json",
23
+ "Accept" => "application/json"}
24
+
25
+ # Create the real json
26
+ bamboo_json = {}
27
+ bamboo_json["id"] = (app_id[0] == '/') ? app_id : ("/" + app_id)
28
+ bamboo_json["acl"] = bamboo_spec["acl"]
29
+
30
+ # curl -i -X PUT -d '{"id":"/ExampleAppGroup/app1", "acl":"path_beg -i /group/app-1"}' http://localhost:8000/api/services//ExampleAppGroup/app1
31
+ # {"/adam-web-dev":{"Id":"/adam-web-dev","Acl":"hdr(host) -i adam-web-dev.ypec.int.yp.com"
32
+ http = Net::HTTP.new(uri.host, uri.port)
33
+ response = http.put("/api/services/#{app_id}", bamboo_json.to_json, json_headers)
34
+
35
+ if response.code == 200.to_s
36
+ puts "successfully created bamboo spec for marathon job: #{app_id}"
37
+ else
38
+ puts "Response #{response.code} #{response.message}: #{response.body}"
39
+ end
40
+
41
+ return response
42
+ end
43
+
44
+ def delete(app_id)
45
+ uri = URI(@config.chronos_url)
46
+ json_headers = {"Content-Type" => "application/json",
47
+ "Accept" => "application/json"}
48
+
49
+ puts "curl -i -X DELETE #{uri}/api/services/#{app_id}"
50
+ http = Net::HTTP.new(uri.host, uri.port)
51
+ response = http.delete("/api/services/#{app_id}", json_headers)
52
+
53
+ if response.code != 200.to_s
54
+ puts "Response #{response.code} #{response.message}: #{response.body}"
55
+ end
56
+
57
+ # TODO: handle error codes better?
58
+
59
+ return response
60
+ end
61
+
62
+ def verify(app_id, spec)
63
+ if @config.check_for_bamboo_url == false
64
+ puts "no bamboo_url - can not verify with server"
65
+ return
66
+ end
67
+
68
+ uri = URI(@config.bamboo_url)
69
+ json_headers = {"Content-Type" => "application/json",
70
+ "Accept" => "application/json"}
71
+
72
+ # TODO: will this work or do I need to parse through all services like chronos
73
+ http = Net::HTTP.new(uri.host, uri.port)
74
+ response = http.get("/api/services", json_headers)
75
+
76
+ if response.code != 200.to_s
77
+ puts "Response #{response.code} #{response.message}: #{response.body}"
78
+ foundDiffs = true
79
+ end
80
+
81
+ allJobs = Hashie::Mash.new(JSON.parse(response.body))
82
+
83
+ # Bamboo api only returns all items
84
+ jobFound = false
85
+ allJobs.each do |key, job|
86
+ if key == app_id
87
+ jobFound = true
88
+ # Bamboo returns keys with different case then you send them!
89
+ # Right now the only field to compar is Acl so we only check it by hand
90
+ if spec["acl"] != job["Acl"]
91
+ printf "difference for field: acl\n"
92
+ printf " spec: #{spec["acl"]}\n"
93
+ printf " server: #{job["Acl"]}\n"
94
+ foundDiffs = true
95
+ end
96
+
97
+
98
+ end
99
+ end
100
+
101
+ if !jobFound
102
+ puts "bamboo spec for marathon job \"#{app_id}\" not currently deployed"
103
+ foundDiffs = true
104
+ end
105
+
106
+ # TODO: handle error codes better?
107
+
108
+ return foundDiffs
109
+ end
110
+
111
+ end
112
+ end
@@ -1,3 +1,4 @@
1
+ # Chronos interface object
1
2
  require 'json'
2
3
  require 'net/http'
3
4
  require 'uri'
@@ -11,20 +12,27 @@ class String
11
12
  end
12
13
 
13
14
  module Orch
14
- class Deploy
15
+ class Chronos
15
16
  def initialize(options)
16
17
  # TODO: get chronos and marathon urls from diffferent ways: param, env, .config
17
18
  @config = Orch::Config.new(options)
18
19
  end
19
20
 
20
- def deploy_chronos(json_payload)
21
+ def deploy(json_payload)
21
22
  uri = URI(@config.chronos_url)
22
23
  json_headers = {"Content-Type" => "application/json",
23
24
  "Accept" => "application/json"}
24
25
 
25
- # curl -L -H 'Content-Type: application/json' -X POST -d @$schedule_file $CHRONOS_URL/scheduler/iso8601
26
+ path = nil
27
+ path = "/scheduler/iso8601" unless json_payload["schedule"].nil?
28
+ path = "/scheduler/dependency" unless json_payload["parents"].nil?
29
+ if path.nil?
30
+ puts "neither schedule nor parents fields defined for Chronos job"
31
+ exit 1
32
+ end
33
+
26
34
  http = Net::HTTP.new(uri.host, uri.port)
27
- response = http.post("/scheduler/iso8601", json_payload, json_headers)
35
+ response = http.post(path, json_payload, json_headers)
28
36
 
29
37
  if response.code != 204.to_s
30
38
  puts "Response #{response.code} #{response.message}: #{response.body}"
@@ -35,7 +43,25 @@ module Orch
35
43
  return response
36
44
  end
37
45
 
38
- def verify_chronos(json_payload)
46
+ def delete(name)
47
+ uri = URI(@config.chronos_url)
48
+ json_headers = {"Content-Type" => "application/json",
49
+ "Accept" => "application/json"}
50
+
51
+ # curl -L -X DELETE chronos-node:8080/scheduler/job/request_event_counter_hourly
52
+ http = Net::HTTP.new(uri.host, uri.port)
53
+ response = http.delete("/scheduler/job/#{name}", json_headers)
54
+
55
+ if response.code != 204.to_s
56
+ puts "Response #{response.code} #{response.message}: #{response.body}"
57
+ end
58
+
59
+ # TODO: handle error codes better?
60
+
61
+ return response
62
+ end
63
+
64
+ def verify(json_payload)
39
65
  if @config.check_for_chronos_url == false
40
66
  puts "no chronos_url - can not verify with server"
41
67
  return
@@ -47,16 +73,17 @@ module Orch
47
73
  json_headers = {"Content-Type" => "application/json",
48
74
  "Accept" => "application/json"}
49
75
 
50
- # curl -L -H 'Content-Type: application/json' -X POST -d @$schedule_file $CHRONOS_URL/scheduler/iso8601
51
76
  http = Net::HTTP.new(uri.host, uri.port)
52
- response = http.get("/scheduler/jobs", json_headers)
77
+ response = http.get("/scheduler/jobs/search?name=#{spec.name}", json_headers)
53
78
 
54
79
  if response.code != 200.to_s
55
80
  puts "Response #{response.code} #{response.message}: #{response.body}"
81
+ foundDiffs = true
56
82
  end
57
83
 
58
84
  array = JSON.parse(response.body).map { |hash| Hashie::Mash.new(hash) }
59
85
 
86
+ # Chronos search API could return more than one item - make sure we find the exact match
60
87
  jobFound = false
61
88
  array.each do |job|
62
89
  if job.name == spec.name
@@ -67,11 +94,12 @@ module Orch
67
94
 
68
95
  if !jobFound
69
96
  puts "job \"#{spec.name}\" not currently deployed"
97
+ foundDiffs = true
70
98
  end
71
99
 
72
100
  # TODO: handle error codes better?
73
101
 
74
- return response
102
+ return foundDiffs
75
103
  end
76
104
 
77
105
  def find_diffs(spec, job)
@@ -84,7 +112,16 @@ module Orch
84
112
  end
85
113
  next
86
114
  end
87
- # TODO: not sure how to compare arrays
115
+ if spec[key].is_a?(Array)
116
+ if spec[key].length != job[key].length
117
+ printf "difference for field: #{key} - length of array is different\n"
118
+ printf " spec: #{spec[key].to_json}\n"
119
+ printf " server: #{job[key].to_json}\n"
120
+ foundDiff = true
121
+ next
122
+ end
123
+ # TODO: not sure how to compare arrays
124
+ end
88
125
  specVal = spec[key]
89
126
  jobVal = job[key]
90
127
  if spec[key].to_s.numeric?
@@ -94,66 +131,23 @@ module Orch
94
131
  specVal = spec[key]
95
132
  jobVal = job[key]
96
133
  end
134
+ # Chronos changes the case of the Docker argument for some reason
135
+ if key == "type"
136
+ specVal = specVal.upcase
137
+ jobVal = jobVal.upcase
138
+ end
97
139
  if specVal != jobVal
98
- puts "#{key}= spec:#{specVal}, server:#{jobVal}"
140
+ if foundDiff == false
141
+ puts "Differences found in job"
142
+ end
143
+ printf "difference for field: #{key}\n"
144
+ printf " spec: #{specVal}\n"
145
+ printf " server: #{jobVal}\n"
99
146
  foundDiff = true
100
147
  end
101
148
  end
102
149
 
103
150
  return foundDiff
104
151
  end
105
-
106
- def deploy_marathon(json_payload)
107
- uri = URI(@config.marathon_url)
108
- json_headers = {"Content-Type" => "application/json",
109
- "Accept" => "application/json"}
110
- puts uri
111
-
112
- http = Net::HTTP.new(uri.host, uri.port)
113
- response = http.put("/v2/apps/#{json_payload["id"]}", json_payload, json_headers)
114
-
115
- puts "Response #{response.code} #{response.message}: #{response.body}"
116
-
117
- if response.code == 204.to_s
118
- puts "success"
119
- end
120
-
121
- # TODO: handle error codes
122
-
123
- return response
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
-
158
152
  end
159
- end
153
+ end
data/lib/config.rb CHANGED
@@ -32,6 +32,14 @@ module Orch
32
32
  end
33
33
  end
34
34
 
35
+ def check_for_bamboo_url
36
+ if (! @options.has_key?("bamboo_url")) && (@APP_CONFIG.nil? || @APP_CONFIG["bamboo_url"].nil?)
37
+ return false
38
+ else
39
+ return true
40
+ end
41
+ end
42
+
35
43
  def chronos_url
36
44
  if @options.has_key?("chronos_url")
37
45
  # If passed in on command line override what is in config file
@@ -62,13 +70,32 @@ module Orch
62
70
  return @APP_CONFIG["marathon_url"]
63
71
  end
64
72
 
65
- def setup_config(marathon_url, chronos_url)
73
+ def bamboo_url
74
+ if @options.has_key?("bamboo_url")
75
+ # If passed in on command line override what is in config file
76
+ url = @options["bamboo_url"]
77
+ return url
78
+ end
79
+
80
+ if @APP_CONFIG.nil? || @APP_CONFIG["bamboo_url"].nil?
81
+ puts "bamboo_url not specified, use --bamboo_url or set in ~/.orch/config.yml"
82
+ exit 1
83
+ end
84
+
85
+ return @APP_CONFIG["bamboo_url"]
86
+ end
87
+
88
+ def setup_config(settings)
66
89
 
67
90
  if @APP_CONFIG.nil?
68
91
  @APP_CONFIG = {}
69
92
  end
70
- @APP_CONFIG['marathon_url'] = marathon_url
71
- @APP_CONFIG['chronos_url'] = chronos_url
93
+
94
+ settings.each do |key, value|
95
+ if settings[key] != ""
96
+ @APP_CONFIG[key] = value
97
+ end
98
+ end
72
99
 
73
100
  if ! File.directory?("#{Dir.home}/.orch")
74
101
  Dir.mkdir("#{Dir.home}/.orch")
data/lib/marathon.rb ADDED
@@ -0,0 +1,150 @@
1
+ # Marathon interface object
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'uri'
5
+
6
+ require 'config'
7
+
8
+ class String
9
+ def numeric?
10
+ Float(self) != nil rescue false
11
+ end
12
+ end
13
+
14
+ module Orch
15
+ class Marathon
16
+ def initialize(options)
17
+ # TODO: get chronos and marathon urls from diffferent ways: param, env, .config
18
+ @config = Orch::Config.new(options)
19
+ end
20
+
21
+ def deploy(app_id, json_payload)
22
+ uri = URI(@config.marathon_url)
23
+ json_headers = {"Content-Type" => "application/json",
24
+ "Accept" => "application/json"}
25
+
26
+ http = Net::HTTP.new(uri.host, uri.port)
27
+ response = http.put("/v2/apps/#{app_id}", json_payload, json_headers)
28
+
29
+ # TODO: should we do anyting with version or deploymentId that gets returned?
30
+ if response.code == 201.to_s
31
+ puts "successfully created marathon job: #{app_id}"
32
+ elsif response.code == 200.to_s
33
+ puts "successfully updated marathon job: #{app_id}"
34
+ else
35
+ puts "Response #{response.code} #{response.message}: #{response.body}"
36
+ end
37
+
38
+ return response
39
+ end
40
+
41
+ def delete(id)
42
+ uri = URI(@config.marathon_url)
43
+ json_headers = {"Content-Type" => "application/json",
44
+ "Accept" => "application/json"}
45
+
46
+ http = Net::HTTP.new(uri.host, uri.port)
47
+ response = http.delete("/v2/apps/#{id}", json_headers)
48
+
49
+ if response.code == 200.to_s
50
+ puts "successfully deleted #{id}"
51
+ elsif response.code == 404.to_s
52
+ puts "job: #{id} - does not exist to delete"
53
+ else
54
+ puts "Response #{response.code} #{response.message}: #{response.body}"
55
+ end
56
+
57
+ return response
58
+ end
59
+
60
+ def verify(json_payload)
61
+ if @config.check_for_marathon_url == false
62
+ puts "no marathon_url - can not verify with server"
63
+ return
64
+ end
65
+
66
+ spec = Hashie::Mash.new(JSON.parse(json_payload))
67
+
68
+ uri = URI(@config.marathon_url)
69
+ json_headers = {"Content-Type" => "application/json",
70
+ "Accept" => "application/json"}
71
+
72
+ http = Net::HTTP.new(uri.host, uri.port)
73
+ response = http.get("/v2/apps/#{spec.id}", json_headers)
74
+
75
+ if response.code == 200.to_s
76
+ job = Hashie::Mash.new(JSON.parse(response.body))
77
+ foundDiffs = find_diffs(spec, job.app)
78
+ elsif response.code == 404.to_s
79
+ puts "job: #{spec.id} - not defined in Marathon"
80
+ foundDiffs = true
81
+ else
82
+ puts "Response #{response.code} #{response.message}: #{response.body}"
83
+ foundDiffs = true
84
+ end
85
+
86
+ return foundDiffs
87
+ end
88
+
89
+ def restart(app_id)
90
+ # POST /v2/apps/{appId}/restart: Rolling restart of all tasks of the given app
91
+ uri = URI(@config.marathon_url)
92
+ json_headers = {"Content-Type" => "application/json",
93
+ "Accept" => "application/json"}
94
+
95
+ http = Net::HTTP.new(uri.host, uri.port)
96
+ response = http.post("/v2/apps/#{app_id}/restart", {}.to_json, json_headers)
97
+
98
+ if response.code == 200.to_s
99
+ puts "success"
100
+ else
101
+ puts "Response #{response.code} #{response.message}: #{response.body}"
102
+ end
103
+
104
+ return response
105
+ end
106
+
107
+ def find_diffs(spec, job)
108
+ foundDiff = false
109
+
110
+ spec.each_key do |key|
111
+ if spec[key].is_a?(Hash)
112
+ if find_diffs(spec[key], job[key]) == true
113
+ foundDiff = true
114
+ end
115
+ next
116
+ end
117
+ if spec[key].is_a?(Array)
118
+ if spec[key].length != job[key].length
119
+ printf "difference for field: #{key} - length of array is different\n"
120
+ printf " spec: #{spec[key].to_json}\n"
121
+ printf " server: #{job[key].to_json}\n"
122
+ foundDiff = true
123
+ end
124
+ # TODO: this will not work if arrays are not in same order
125
+ spec[key].zip(job[key]).each do |subSpec, subJob|
126
+ if find_diffs(subSpec, subJob) == true
127
+ foundDiff = true
128
+ end
129
+ next
130
+ end
131
+ next
132
+ end
133
+ specVal = spec[key]
134
+ jobVal = job[key]
135
+ if spec[key].to_s.numeric?
136
+ specVal = Float(spec[key])
137
+ jobVal = Float(job[key])
138
+ end
139
+ if specVal != jobVal
140
+ printf "difference for field: #{key}\n"
141
+ printf " spec: #{specVal}\n"
142
+ printf " server: #{jobVal}\n"
143
+ foundDiff = true
144
+ end
145
+ end
146
+
147
+ return foundDiff
148
+ end
149
+ end
150
+ end
data/lib/orch/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Orch
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/orch.rb CHANGED
@@ -4,7 +4,9 @@ require 'json'
4
4
  require 'thor'
5
5
  require "yaml"
6
6
  require "parse"
7
- require "deploy"
7
+ require "chronos"
8
+ require "marathon"
9
+ require "bamboo"
8
10
 
9
11
  module Orch
10
12
  class Application < Thor
@@ -21,16 +23,18 @@ module Orch
21
23
  end
22
24
  end
23
25
  say("Enter values to construct a ~/.orch/config.yaml file")
24
- marathon_url = ask("Marathon URL: ")
25
- chronos_url = ask("Chronos URL: ")
26
+ settings = {}
27
+ settings["marathon_url"] = ask("Marathon URL: ")
28
+ settings["chronos_url"] = ask("Chronos URL: ")
29
+ settings["bamboo_url"] = ask("Bamboo URL: ")
26
30
 
27
- config.setup_config(marathon_url, chronos_url)
31
+ config.setup_config(settings)
28
32
  end
29
33
 
30
34
  option :deploy_kind, :default => 'all',
31
35
  :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'
36
+ option :deploy_var, :default => 'all',
37
+ :desc => 'DEPLOY_VAR=VALUE deploys only if a deploy_var matches the given value'
34
38
  option :subst,
35
39
  :desc => 'KEY=VALUE substitute KEY with VALUE globaly in your config'
36
40
  option :show_json, :default => false,
@@ -42,7 +46,10 @@ module Orch
42
46
  parser = Orch::Parse.new(file_name, options)
43
47
  result = parser.parse(true)
44
48
  puts "Number of configs found: #{result.length}"
45
- deploy = Orch::Deploy.new(options)
49
+
50
+ marathon = Orch::Marathon.new(options)
51
+ chronos = Orch::Chronos.new(options)
52
+ bamboo = Orch::Bamboo.new(options)
46
53
  result.each do |app|
47
54
  printf "Name: %s, Type: %s, Deploy?: %s", app[:name], app[:type], app[:deploy]
48
55
  app[:env_vars].each do |key, value|
@@ -53,23 +60,33 @@ module Orch
53
60
  pretty = JSON.pretty_generate(app[:json])
54
61
  puts "JSON: #{pretty}"
55
62
  end
63
+ foundDiffs = false
56
64
  if (app[:type] == "Chronos") && (options[:server_verify] == true)
57
- deploy.verify_chronos(app[:json].to_json)
65
+ foundDiffs = chronos.verify(app[:json].to_json)
58
66
  end
59
67
  if (app[:type] == "Marathon") && (options[:server_verify] == true)
60
- deploy.verify_marathon(app[:json].to_json)
68
+ foundDiffs = marathon.verify(app[:json].to_json)
69
+ if app[:bamboo_spec]
70
+ bambooDiffs = bamboo.verify(app[:name], app[:bamboo_spec])
71
+ foundDiffs = foundDiffs || bambooDiffs
72
+ end
73
+ end
74
+ if (!foundDiffs) && (options[:server_verify] == true)
75
+ puts "No differences with server found"
61
76
  end
62
77
  end
63
78
  end
64
79
 
65
80
  option :deploy_kind, :default => 'all',
66
81
  :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'
82
+ option :deploy_var, :default => 'all',
83
+ :desc => 'DEPLOY_VAR=VALUE deploys only if a deploy_var matches the given value'
69
84
  option :chronos_url,
70
85
  :desc => 'url to chronos master'
71
86
  option :marathon_url,
72
87
  :desc => 'url to marathon master'
88
+ option :bamboo_url,
89
+ :desc => 'url to bamboo server'
73
90
  option :subst,
74
91
  :desc => 'KEY=VALUE substitute KEY with VALUE globaly in your config'
75
92
  desc 'deploy PATH', 'Deploys config to mesos frameworks.'
@@ -81,7 +98,9 @@ module Orch
81
98
  puts "nothing found to deploy"
82
99
  end
83
100
 
84
- deploy = Orch::Deploy.new(options)
101
+ marathon = Orch::Marathon.new(options)
102
+ chronos = Orch::Chronos.new(options)
103
+ bamboo = Orch::Bamboo.new(options)
85
104
  result.each do |app|
86
105
  if !app[:deploy]
87
106
  puts "skipping app: #{app[:name]}"
@@ -90,13 +109,88 @@ module Orch
90
109
  puts "deploying #{app[:name]} to #{app[:type]}"
91
110
  #puts "#{app[:json]}" - should I support show_json here as well?
92
111
  if app[:type] == "Chronos"
93
- deploy.deploy_chronos(app[:json].to_json)
112
+ chronos.deploy(app[:json].to_json)
94
113
  end
95
114
  if app[:type] == "Marathon"
96
- deploy.deploy_marathon(app[:json].to_json)
115
+ marathon.deploy(app[:name], app[:json].to_json)
116
+ if app[:bamboo_spec]
117
+ bamboo.deploy(app[:name], app[:bamboo_spec])
118
+ end
97
119
  end
98
120
  end
99
121
  end
100
122
 
123
+ option :deploy_kind, :default => 'all',
124
+ :desc => 'deletes only the given application kind: chronos, marathon, all'
125
+ option :deploy_var, :default => 'all',
126
+ :desc => 'DEPLOY_VAR=VALUE deletes only if a deploy_var matches the given value'
127
+ option :chronos_url,
128
+ :desc => 'url to chronos master'
129
+ option :marathon_url,
130
+ :desc => 'url to marathon master'
131
+ option :bamboo_url,
132
+ :desc => 'url to bamboo server'
133
+ option :subst,
134
+ :desc => 'KEY=VALUE substitute KEY with VALUE globaly in your config'
135
+ desc 'delete PATH', 'Deletes config from mesos frameworks.'
136
+ def delete(file_name)
137
+ parser = Orch::Parse.new(file_name, options)
138
+ result = parser.parse(false)
139
+
140
+ if result.length == 0
141
+ puts "nothing found to delete"
142
+ end
143
+
144
+ marathon = Orch::Marathon.new(options)
145
+ chronos = Orch::Chronos.new(options)
146
+ bamboo = Orch::Bamboo.new(options)
147
+
148
+ result.each do |app|
149
+ if !app[:deploy]
150
+ puts "skipping app: #{app[:name]}"
151
+ next
152
+ end
153
+ puts "deleting #{app[:name]} from #{app[:type]}"
154
+ if app[:type] == "Chronos"
155
+ chronos.delete(app[:name])
156
+ end
157
+ if app[:type] == "Marathon"
158
+ marathon.delete(app[:name])
159
+ if app[:bamboo_spec]
160
+ bamboo.delete(app[:name])
161
+ end
162
+ end
163
+ end
164
+ end
165
+
166
+ option :deploy_kind, :default => 'all',
167
+ :desc => 'deletes only the given application kind: chronos, marathon, all'
168
+ option :deploy_var, :default => 'all',
169
+ :desc => 'DEPLOY_VAR=VALUE deletes only if a deploy_var matches the given value'
170
+ option :marathon_url,
171
+ :desc => 'url to marathon master'
172
+ option :subst,
173
+ :desc => 'KEY=VALUE substitute KEY with VALUE globaly in your config'
174
+ desc 'restart PATH', 'Restarts specified application(s) on server'
175
+ def restart(file_name)
176
+ parser = Orch::Parse.new(file_name, options)
177
+ result = parser.parse(false)
178
+
179
+ if result.length == 0
180
+ puts "nothing found to restart"
181
+ end
182
+
183
+ marathon = Orch::Marathon.new(options)
184
+ result.each do |app|
185
+ if !app[:deploy] || (app[:type] == "Chronos")
186
+ puts "skipping app: #{app[:name]}"
187
+ next
188
+ end
189
+ puts "restarting #{app[:name]} on #{app[:type]}"
190
+ if app[:type] == "Marathon"
191
+ marathon.restart(app[:name])
192
+ end
193
+ end
194
+ end
101
195
  end
102
196
  end
data/lib/parse.rb CHANGED
@@ -9,14 +9,13 @@ module Orch
9
9
  puts "file does not exist: #{path}"
10
10
  exit 1
11
11
  end
12
- # TODO: try resecue for any syntax issues in yaml file
12
+
13
13
  begin
14
14
  yaml = ::YAML.load_file(path)
15
15
  rescue Psych::SyntaxError => e
16
16
  puts "error parsing yaml file #{e}"
17
17
  exit 1
18
18
  end
19
- #puts yaml.to_json
20
19
 
21
20
  @options = options
22
21
 
@@ -42,6 +41,11 @@ module Orch
42
41
  # Check for vault vars
43
42
  env_var_values = parse_vault_vars(@spec)
44
43
 
44
+ # Check for env values at spec level
45
+ if ! spec.env.nil?
46
+ env_var_values = env_var_values.merge(spec.env)
47
+ end
48
+
45
49
  if spec.applications.nil?
46
50
  puts "required section applications: must have at least one application defined"
47
51
  exit 1
@@ -60,39 +64,51 @@ module Orch
60
64
  exit 1
61
65
  end
62
66
 
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)
67
+ # Generate any deploy variables that need to be merged in
68
+ deploy_vars = parse_deploy_vars(app)
69
+ app_var_values = env_var_values.merge(deploy_vars)
70
+
71
+ # Check for env values at app level
72
+ if ! app.env.nil?
73
+ app_var_values = app_var_values.merge(app.env)
74
+ end
66
75
 
67
76
  if (app.kind == "Chronos")
68
- chronos_spec = parse_chronos(app, env_var_values)
77
+ chronos_spec = parse_chronos(app, app_var_values)
69
78
 
70
- result = {:name => chronos_spec["name"], :type => app.kind, :deploy => should_deploy?(app), :env_vars => env_var_values, :json => chronos_spec}
79
+ result = {:name => chronos_spec["name"], :type => app.kind, :deploy => should_deploy?(app), :env_vars => deploy_vars, :json => chronos_spec}
71
80
  results << result
72
81
  end
73
82
 
74
83
  if (app.kind == "Marathon")
75
- marathon_spec = parse_marathon(app, env_var_values)
84
+ marathon_spec = parse_marathon(app, app_var_values)
85
+
86
+ result = {:name => marathon_spec["id"], :type => app.kind, :deploy => should_deploy?(app), :env_vars => deploy_vars, :json => marathon_spec}
87
+
88
+ if app.bamboo_spec
89
+ bamboo_spec = parse_bamboo(app, app_var_values)
90
+ result[:bamboo_spec] = bamboo_spec
91
+ end
76
92
 
77
- result = {:name => marathon_spec["id"], :type => app.kind, :deploy => should_deploy?(app), :env_vars => env_var_values, :json => marathon_spec}
78
93
  results << result
79
94
  end
95
+
80
96
  end
81
97
 
82
98
  return results
83
99
  end
84
100
 
85
- def parse_env_vars(app)
101
+ def parse_deploy_vars(app)
86
102
  result = {}
87
- if (! @spec.environment_vars.nil?)
88
- @spec.environment_vars.each do |key, value|
103
+ if (! @spec.deploy_vars.nil?)
104
+ @spec.deploy_vars.each do |key, value|
89
105
  if app[key].nil?
90
106
  puts "environments_var #{key} specified - but not included in app"
91
107
  # TODO: would be nice to put the app name...
92
108
  exit 1
93
109
  end
94
- if ! @spec.environment_vars[key].include? app[key]
95
- puts "#{key} value \"#{app[key]}\" not in #{@spec.environment_vars[key].to_s}"
110
+ if ! @spec.deploy_vars[key].include? app[key]
111
+ puts "#{key} value \"#{app[key]}\" not in #{@spec.deploy_vars[key].to_s}"
96
112
  exit 1
97
113
  end
98
114
  result[key] = app[key]
@@ -115,29 +131,50 @@ module Orch
115
131
  end
116
132
 
117
133
  def parse_chronos(app, env_var_values)
118
- # TODO: check if it exists
119
- cronos_spec = app.cronos_spec
134
+ if app.chronos_spec.nil?
135
+ puts "App of kind: Chronos requires a 'chronos_spec:' field"
136
+ exit 1
137
+ end
138
+ chronos_spec = app.chronos_spec
120
139
 
121
- # Augment any spec environment variables with meta values
122
- env_var_values.each do |key, value|
140
+ # Override out high-level env vars with any chronos_spec level vars
141
+ env_vars = env_var_values
142
+ (chronos_spec.environmentVariables || []).each do |x|
143
+ env_vars[x["name"]] = x["value"]
144
+ end
145
+
146
+ # Rewrite the environmentVariables from the hash
147
+ chronos_spec.environmentVariables = []
148
+ env_vars.each do |key, value|
123
149
  pair = {"name" => key, "value" => value}
124
- cronos_spec.environmentVariables << pair
150
+ chronos_spec.environmentVariables << pair
125
151
  end
126
152
 
127
153
  # Do subst processing
128
- spec_str = do_subst(cronos_spec, app)
129
- cronos_spec = JSON.parse(spec_str)
154
+ spec_str = do_subst(chronos_spec, app)
155
+ chronos_spec = JSON.parse(spec_str)
130
156
 
131
- return cronos_spec
157
+ return chronos_spec
132
158
  end
133
159
 
134
160
  def parse_marathon(app, env_var_values)
135
- # TODO: check if it exists
161
+ if app.marathon_spec.nil?
162
+ puts "App of kind: Marathon requires a 'marathon_spec:' field"
163
+ exit 1
164
+ end
136
165
  marathon_spec = app.marathon_spec
137
166
 
138
- # Augment any spec environment variables with meta values
167
+ # Augment any spec environment variables with meta values - but don't overwite
168
+ marathon_spec.env = {} unless marathon_spec.env
139
169
  env_var_values.each do |key, value|
140
- marathon_spec.env[key] = value
170
+ marathon_spec.env[key] = value.to_s unless marathon_spec.env[key]
171
+ end
172
+
173
+ if marathon_spec.id
174
+ marathon_spec.id = (marathon_spec.id[0] == '/') ? marathon_spec.id : ("/" + marathon_spec.id)
175
+ else
176
+ puts "id: is a required field for a marathon spec"
177
+ exit 1
141
178
  end
142
179
 
143
180
  spec_str = do_subst(marathon_spec, app)
@@ -146,25 +183,34 @@ module Orch
146
183
  return marathon_spec
147
184
  end
148
185
 
186
+ def parse_bamboo(app, env_var_values)
187
+ # Do any substs
188
+ spec_str = do_subst(app.bamboo_spec, app)
189
+ bamboo_spec = JSON.parse(spec_str)
190
+
191
+ if bamboo_spec['acl'].nil?
192
+ puts "required field 'acl:' missing from bamboo_spec"
193
+ end
194
+
195
+ return bamboo_spec
196
+ end
197
+
149
198
  def should_deploy?(app)
150
199
  result = true
151
- if (app.kind == "Marathon") && @options[:deploy_kind] == 'chronos'
152
- result = false
153
- end
154
- if (app.kind == "Chronos") && @options[:deploy_kind] == 'marathon'
200
+ if @options[:deploy_kind] != 'all' && app.kind != @options[:deploy_kind]
155
201
  result = false
156
202
  end
157
203
 
158
- if @options[:deploy_env] != 'all'
159
- @options[:deploy_env].split(",").each do |x|
204
+ if @options[:deploy_var] != 'all'
205
+ @options[:deploy_var].split(",").each do |x|
160
206
  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"
207
+ deployVar = pair[0]
208
+ deployVal = pair[1]
209
+ if app[deployVar].nil?
210
+ puts "environment var of '#{deployVar}' not found in app"
165
211
  exit 1
166
212
  end
167
- if app[envVar] != envVal
213
+ if app[deployVar] != deployVal
168
214
  result = false
169
215
  end
170
216
  end
@@ -176,9 +222,9 @@ module Orch
176
222
  def do_subst(spec, app)
177
223
  spec_str = spec.to_json.to_s
178
224
 
179
- # Subst any of the environment_vars values
180
- if (! @spec.environment_vars.nil?)
181
- @spec.environment_vars.each do |key, value|
225
+ # Subst any of the deploy_vars values
226
+ if (! @spec.deploy_vars.nil?)
227
+ @spec.deploy_vars.each do |key, value|
182
228
  spec_str = spec_str.gsub(/{{#{key}}}/, app[key])
183
229
  end
184
230
  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.2
4
+ version: 0.0.3
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-25 00:00:00.000000000 Z
11
+ date: 2015-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,11 +81,15 @@ files:
81
81
  - Rakefile
82
82
  - bin/orch
83
83
  - examples/Examples.md
84
+ - examples/bamboo-ex.yml
84
85
  - examples/env-chronos.yml
86
+ - examples/env-marathon.yml
85
87
  - examples/simple-chronos.yml
86
88
  - examples/simple-marathon.yml
89
+ - lib/bamboo.rb
90
+ - lib/chronos.rb
87
91
  - lib/config.rb
88
- - lib/deploy.rb
92
+ - lib/marathon.rb
89
93
  - lib/orch.rb
90
94
  - lib/orch/version.rb
91
95
  - lib/parse.rb