orats 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +70 -69
- data/lib/orats/cli.rb +18 -30
- data/lib/orats/commands/common.rb +1 -1
- data/lib/orats/commands/diff/compare.rb +73 -68
- data/lib/orats/commands/diff/exec.rb +28 -54
- data/lib/orats/commands/inventory.rb +0 -21
- data/lib/orats/commands/playbook.rb +40 -1
- data/lib/orats/commands/ui.rb +0 -5
- data/lib/orats/templates/includes/playbook/Galaxyfile +2 -2
- data/lib/orats/templates/playbook.rb +10 -16
- data/lib/orats/version.rb +1 -1
- data/test/integration/cli_test.rb +65 -7
- data/test/test_helper.rb +3 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66f5f6015804945e89a0b85282a9a509a9651b1e
|
4
|
+
data.tar.gz: fa9b364b8cfaa9065fd9379b4f75dff5244199ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bfa04d6b0599aca03c1a975c703d977a74b013879fad65d4cacb62b7196309bb85130110a651bb919253066740c9e5fc357dbd500f9d453effb2e6c8eb1a1d2
|
7
|
+
data.tar.gz: 82a0cc18403d621958a1b52ce46d26e1703b3e814e2badd8e62b3e86ccc5ba140e5947071de83584de4e37ae3a1bf6be24ae82e224e7869968cf4291141388c0
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ This readme file is based off the master version of orats. If you want accurate
|
|
5
5
|
|
6
6
|
## What is orats and what problem does it solve?
|
7
7
|
|
8
|
-
It stands for opinionated rails application templates. The templates include solving tedious tasks that you would do for most projects. It handles creating a rails application with a bunch of opinions and optionally an ansible inventory/playbook so you can
|
8
|
+
It stands for opinionated rails application templates. The templates include solving tedious tasks that you would do for most projects. It handles creating a rails application with a bunch of opinions and optionally an ansible inventory/playbook so you can provision your servers and deploy your apps effortlessly.
|
9
9
|
|
10
10
|
## What version of Rails and Ruby are you targeting?
|
11
11
|
|
@@ -20,11 +20,11 @@ Gems will also be updated once they are proven to work on the target rails/ruby
|
|
20
20
|
- [Project](#project)
|
21
21
|
- [Inventory](#inventory)
|
22
22
|
- [Try it](#try-the-inventory-command)
|
23
|
-
- [FAQ](#inventory-faq)
|
24
|
-
- [What's with the sudo password](#whats-with-the-sudo-password)
|
25
23
|
- [Playbook](#playbook)
|
26
24
|
- [Try it](#try-the-playbook-command)
|
27
25
|
- [Ansible roles](#ansible-roles-used)
|
26
|
+
- [FAQ](#playbook-faq)
|
27
|
+
- [What is the Galaxyfile?](#what-is-the-galaxyfile)
|
28
28
|
- [Diff](#diff)
|
29
29
|
- [Try it](#try-the-diff-command)
|
30
30
|
- [Templates](#templates)
|
@@ -96,15 +96,9 @@ Here is an overview of the available commands. You can find out more information
|
|
96
96
|
- Project:
|
97
97
|
- Optionally takes: `--skip-ansible [false]`
|
98
98
|
- Optionally takes: `--skip-server-start [false]`
|
99
|
-
- Ansible:
|
100
|
-
- Optionally takes: `--sudo-password []`
|
101
|
-
- Optionally takes: `--skip-galaxy [false]`
|
102
99
|
|
103
100
|
- **Create an ansible inventory**:
|
104
101
|
- `orats inventory <TARGET_PATH>`
|
105
|
-
- Configuration:
|
106
|
-
- Optionally takes: `--sudo-password []`
|
107
|
-
- Optionally takes: `--skip-galaxy [false]`
|
108
102
|
|
109
103
|
- **Create an ansible playbook**:
|
110
104
|
- `orats playbook <TARGET_PATH>`
|
@@ -115,11 +109,13 @@ Here is an overview of the available commands. You can find out more information
|
|
115
109
|
- `orats nuke <TARGET_PATH>`
|
116
110
|
- Optionally takes: `--skip-data [false]`
|
117
111
|
|
118
|
-
- **Compare differences between orats
|
112
|
+
- **Compare differences between your orats files and the latest version's
|
113
|
+
files**:
|
119
114
|
- `orats diff [options]`
|
115
|
+
- Optionally takes: `--galaxyfile []`
|
116
|
+
- Optionally takes: `--playbook []`
|
120
117
|
- Optionally takes: `--hosts []`
|
121
118
|
- Optionally takes: `--inventory []`
|
122
|
-
- Optionally takes: `--playbook []`
|
123
119
|
|
124
120
|
- **Get a list of available orats templates**:
|
125
121
|
- `orats templates`
|
@@ -167,31 +163,11 @@ You may also consider using this command if you happen to use ansible but are
|
|
167
163
|
- This could be used to send to your servers
|
168
164
|
- Create self signed ssl certificates to test/support ssl
|
169
165
|
- Create a monit pem file for its optional http interface over ssl
|
170
|
-
- Galaxy install the roles required by an orats project
|
171
|
-
- Optionally turned off with `--skip-galaxy`
|
172
166
|
|
173
167
|
#### Try the inventory command
|
174
168
|
|
175
169
|
`orats inventory myinventory`
|
176
170
|
|
177
|
-
#### Inventory FAQ
|
178
|
-
|
179
|
-
##### What's with the sudo password flag?
|
180
|
-
|
181
|
-
Ansible can be installed in a number of ways. A common way is to build a package or use a package manager. When you install ansible this way it
|
182
|
-
gets installed to `/etc/ansible`.
|
183
|
-
|
184
|
-
By default ansible will download roles from the galaxy to
|
185
|
-
`/etc/ansible/roles` which will require sudo to write to.
|
186
|
-
|
187
|
-
If you installed ansible to your home directory then orats is smart enough
|
188
|
-
not to use sudo. It will only try to use sudo when it detects a permission
|
189
|
-
error.
|
190
|
-
|
191
|
-
You can also choose not to provide the `--sudo-password` flag but then you
|
192
|
-
will be prompted for a sudo password about 90% of the way through the
|
193
|
-
duration of the inventory command.
|
194
|
-
|
195
171
|
### Playbook
|
196
172
|
|
197
173
|
Building your application is only one piece of the puzzle. If you want to ship your application you have to host it somewhere. You have a few options when it comes to managed hosts like Heroku but they tend to be very expensive if you fall out of their free tier.
|
@@ -238,43 +214,78 @@ Everything is broken up into ansible roles so you can quickly scale out horizont
|
|
238
214
|
- `nickjj.nginx` https://github.com/nickjj/ansible-nginx
|
239
215
|
- `DavidWittman.redis` https://github.com/DavidWittman/ansible-redis
|
240
216
|
|
241
|
-
|
217
|
+
#### Playbook FAQ
|
242
218
|
|
243
|
-
|
219
|
+
##### What is the Galaxyfile?
|
220
|
+
|
221
|
+
It is similar to what a Gemfile is for ruby.
|
244
222
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
223
|
+
When you generate a playbook it will create a `roles` folder inside of the
|
224
|
+
target path you specified. The roles folder will contain all of the above
|
225
|
+
roles.
|
226
|
+
|
227
|
+
When you run the playbook it will use these files when it provisions
|
228
|
+
your server(s).
|
249
229
|
|
250
|
-
|
251
|
-
|
252
|
-
or roles and it will also detect custom variables/roles that you have added.
|
253
|
-
|
254
|
-
It allows you to make 2 different types of comparisons:
|
230
|
+
This allows you to easily update the versions of each ansible role without
|
231
|
+
having to download a new version of orats.
|
255
232
|
|
256
|
-
|
233
|
+
##### How do I update the roles for an existing playbook?
|
257
234
|
|
258
|
-
|
259
|
-
|
260
|
-
This is
|
261
|
-
|
262
|
-
|
235
|
+
Just run `orats playbook myplaybook` and it will overwrite
|
236
|
+
the roles in `myplaybook/roles` using the versions supplied in your
|
237
|
+
`Galaxyfile`. This is useful to run when a role requires a bug fix or new features were added.
|
238
|
+
|
239
|
+
Since the roles are self contained in the playbook this allows you to have
|
240
|
+
multiple playbooks with certain role versions in case you have older orats
|
241
|
+
projects which require older role versions.
|
242
|
+
|
243
|
+
### Diff
|
244
|
+
|
245
|
+
The goal of the diff command is to compare your orats generated files with
|
246
|
+
the latest version to see what differences there are between the 2.
|
263
247
|
|
264
|
-
|
248
|
+
You can compare nothing in which case it just gives you back your version of
|
249
|
+
the orats gem vs the latest gem version or you can add paths to 1 or all of the
|
250
|
+
files below.
|
265
251
|
|
266
|
-
|
267
|
-
with a path to each of their files then it will compare the files contained
|
268
|
-
in the orats source code to your custom generated inventory/playbook.
|
252
|
+
##### Galaxyfile
|
269
253
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
254
|
+
When you supply the `--galaxyfile` flag along with a path to your `Galaxyfile`
|
255
|
+
it will show you a list of missing, outdated and extra roles with the versions.
|
256
|
+
|
257
|
+
##### Playbook
|
258
|
+
|
259
|
+
When you supply the `--playbook` flag along with a path to your
|
260
|
+
`site.yml` file it will show you a list of missing or extra roles.
|
261
|
+
|
262
|
+
##### Hosts
|
263
|
+
|
264
|
+
When you supply the `--hosts` flag along with a path to your `hosts` file it
|
265
|
+
will show you a list of missing or extra groups.
|
266
|
+
|
267
|
+
##### Inventory
|
268
|
+
|
269
|
+
When you supply the `--inventory` flag along with a path to your
|
270
|
+
`group_vars/all.yml` file it will show you a list of missing or extra variables.
|
271
|
+
|
272
|
+
#### Wait, there is an easier way to compare everything
|
273
|
+
|
274
|
+
If you kept the default file names for the files orats generated then you can
|
275
|
+
simply pass in the path to your inventory directory and playbook directory and
|
276
|
+
it will compare everything for you. This is much less annoying to type.
|
274
277
|
|
275
278
|
#### Try the diff command
|
276
279
|
|
277
|
-
|
280
|
+
##### Individual files
|
281
|
+
|
282
|
+
`orats diff -g /path/to/playbook/Galaxyfile -p /path/to/playbook/site.yml -h
|
283
|
+
/path/to/project/inventory/hosts -i /path/to/project/inventory/group_vars/all
|
284
|
+
.yml`
|
285
|
+
|
286
|
+
##### Shortcut
|
287
|
+
|
288
|
+
`orats diff -i /path/to/my/project/inventory -p /path/to/playbook`
|
278
289
|
|
279
290
|
### Templates
|
280
291
|
|
@@ -343,7 +354,7 @@ All of the changes have git commits to go with them. After generating a project
|
|
343
354
|
|
344
355
|
#### Try the base template
|
345
356
|
|
346
|
-
`orats project myapp --pg-password foo
|
357
|
+
`orats project myapp --pg-password foo`
|
347
358
|
|
348
359
|
#### Base FAQ
|
349
360
|
|
@@ -353,16 +364,6 @@ Orats will automatically start your server (you can turn this off with a flag) a
|
|
353
364
|
|
354
365
|
In order to do this it must know your postgres location, username and password. By default it will use localhost for the *location* and *postgres* as the username but if you need to supply those values because yours are different you can use `--pg-location foo` and `--pg-username bar`.
|
355
366
|
|
356
|
-
##### What is `--skip-galaxy`?
|
357
|
-
|
358
|
-
By default the project command will generate ansible related files for you so that you can manage this app's "inventory". It also automatically downloads the ansible roles from the [ansible galaxy](https://galaxy.ansible.com/).
|
359
|
-
|
360
|
-
This was done to ensure each app you create has the correct ansible role version to go with it. However, if you installed ansible through apt or somewhere outside of your home directory then you will get permissions errors when it tries to download the roles.
|
361
|
-
|
362
|
-
You can fix this by supplying `--sudo-password foo` to the above command if you know ansible is installed outside of your home directory or you can just wait while the command runs and it will prompt you for your sudo password when it gets to that point because orats will attempt to use sudo only after it fails trying to install the roles without sudo.
|
363
|
-
|
364
|
-
If you don't care about the ansible at all you could add `--skip-ansible` to not generate any ansible files.
|
365
|
-
|
366
367
|
##### Does your redis server use a password?
|
367
368
|
|
368
369
|
If your redis server is configured to use a password then you must also pass in `--redis-password foo`.
|
@@ -461,7 +462,7 @@ All of the changes have git commits to go with them. After generating a project
|
|
461
462
|
|
462
463
|
#### Try the auth template
|
463
464
|
|
464
|
-
`orats project myauthapp --auth --pg-password foo
|
465
|
+
`orats project myauthapp --template auth --pg-password foo`
|
465
466
|
|
466
467
|
#### Auth FAQ
|
467
468
|
|
data/lib/orats/cli.rb
CHANGED
@@ -15,9 +15,7 @@ module Orats
|
|
15
15
|
option :template, default: '', aliases: '-m'
|
16
16
|
option :custom, default: '', aliases: '-c'
|
17
17
|
option :skip_ansible, type: :boolean, default: false, aliases: '-A'
|
18
|
-
option :skip_server_start, type: :boolean, default: false, aliases: '-
|
19
|
-
option :sudo_password, default: '', aliases: '-s'
|
20
|
-
option :skip_galaxy, type: :boolean, default: false, aliases: '-G'
|
18
|
+
option :skip_server_start, type: :boolean, default: false, aliases: '-S'
|
21
19
|
desc 'project TARGET_PATH [options]', ''
|
22
20
|
long_desc <<-D
|
23
21
|
`orats project target_path --pg-password supersecret` will create a new rails project and it will also create an ansible inventory to go with it by default.
|
@@ -47,29 +45,15 @@ module Orats
|
|
47
45
|
`--skip-ansible` skip creating the ansible related directories [false]
|
48
46
|
|
49
47
|
`--skip-server-start` skip automatically running puma and sidekiq [false]
|
50
|
-
|
51
|
-
Ansible features:
|
52
|
-
|
53
|
-
`--sudo-password` to install ansible roles from the galaxy to a path outside of your user privileges []
|
54
|
-
|
55
|
-
`--skip-galaxy` skip automatically installing roles from the galaxy [false]
|
56
48
|
D
|
57
49
|
|
58
50
|
def project(target_path)
|
59
51
|
Commands::Project::Exec.new(target_path, options).init
|
60
52
|
end
|
61
53
|
|
62
|
-
option :sudo_password, default: '', aliases: '-s'
|
63
|
-
option :skip_galaxy, type: :boolean, default: false, aliases: '-G'
|
64
54
|
desc 'inventory TARGET_PATH [options]', ''
|
65
55
|
long_desc <<-D
|
66
56
|
`orats inventory target_path` will create an ansible inventory.
|
67
|
-
|
68
|
-
Configuration:
|
69
|
-
|
70
|
-
`--sudo-password` to install ansible roles from the galaxy to a path outside of your user privileges []
|
71
|
-
|
72
|
-
`--skip-galaxy` skip automatically installing roles from the galaxy [false]
|
73
57
|
D
|
74
58
|
|
75
59
|
def inventory(target_path)
|
@@ -81,9 +65,14 @@ module Orats
|
|
81
65
|
long_desc <<-D
|
82
66
|
`orats playbook target_path` will create an ansible playbook.
|
83
67
|
|
68
|
+
Help:
|
69
|
+
|
70
|
+
If you pass in an existing playbook path it will update the role versions.
|
71
|
+
|
84
72
|
Template features:
|
85
73
|
|
86
|
-
`--custom` will let you supply a custom template, a url or file is ok but urls
|
74
|
+
`--custom` will let you supply a custom template, a url or file is ok but urls
|
75
|
+
must start with http or https []
|
87
76
|
D
|
88
77
|
|
89
78
|
def playbook(target_path)
|
@@ -107,34 +96,33 @@ module Orats
|
|
107
96
|
Commands::Nuke.new(target_path, options).init
|
108
97
|
end
|
109
98
|
|
99
|
+
option :galaxyfile, default: '', aliases: '-g'
|
100
|
+
option :playbook, default: '', aliases: '-p'
|
110
101
|
option :hosts, default: '', aliases: '-h'
|
111
102
|
option :inventory, default: '', aliases: '-i'
|
112
|
-
option :playbook, default: '', aliases: '-b'
|
113
103
|
desc 'diff [options]', ''
|
114
104
|
long_desc <<-D
|
115
105
|
`orats diff` will run various comparisons on orats and your ansible files.
|
116
106
|
|
117
|
-
|
118
|
-
|
119
|
-
`The green/yellow labels` denote a remote check to compare the files contained in your version of orats to the latest files on github.
|
107
|
+
Options:
|
120
108
|
|
121
|
-
`
|
109
|
+
`--galaxyfile` to supply a galaxyfile for comparison []
|
122
110
|
|
123
|
-
|
111
|
+
`--playbook` to supply a playbook directory/file for comparison []
|
124
112
|
|
125
113
|
`--hosts` to supply a hosts file for comparison []
|
126
114
|
|
127
115
|
`--inventory` to supply an inventory directory/file for comparison []
|
128
116
|
|
129
|
-
`--playbook` to supply a playbook directory/file for comparison []
|
130
|
-
|
131
117
|
Quality of life features:
|
132
118
|
|
133
|
-
`--
|
134
|
-
|
135
|
-
|
119
|
+
`--playbook` also accepts a playbook path, if you kept the
|
120
|
+
default file names it will automatically compare both your Galaxyfile and
|
121
|
+
site.yml files.
|
136
122
|
|
137
|
-
`--
|
123
|
+
`--inventory` also accepts an inventory path, if you kept the
|
124
|
+
default file names it will automatically compare both your hosts and
|
125
|
+
group_vars/all.yml files.
|
138
126
|
D
|
139
127
|
|
140
128
|
def diff
|
@@ -12,9 +12,9 @@ module Orats
|
|
12
12
|
|
13
13
|
RELATIVE_PATHS = {
|
14
14
|
galaxyfile: 'templates/includes/playbook/Galaxyfile',
|
15
|
+
playbook: 'templates/includes/playbook/site.yml',
|
15
16
|
hosts: 'templates/includes/inventory/hosts',
|
16
17
|
inventory: 'templates/includes/inventory/group_vars/all.yml',
|
17
|
-
playbook: 'templates/includes/playbook/site.yml',
|
18
18
|
version: 'version.rb'
|
19
19
|
}
|
20
20
|
|
@@ -2,98 +2,103 @@ module Orats
|
|
2
2
|
module Commands
|
3
3
|
module Diff
|
4
4
|
module Compare
|
5
|
-
def
|
6
|
-
log_remote_info 'gem',
|
7
|
-
'version
|
5
|
+
def remote_gem_vs_yours
|
6
|
+
log_remote_info 'gem',
|
7
|
+
'Compare your orats version to the latest version',
|
8
|
+
'version',
|
9
|
+
"You have v#{VERSION} and the latest version is #{@remote_gem_version}"
|
8
10
|
end
|
9
11
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def remote_vs_yours(label, remote, yours, exact_match)
|
13
|
+
log_remote_info label,
|
14
|
+
"Compare your #{label} to the latest version (#{@remote_gem_version})",
|
15
|
+
'file', File.basename(Common::RELATIVE_PATHS[label
|
16
|
+
.to_sym])
|
15
17
|
|
16
|
-
|
18
|
+
outdated_and_missing = difference(remote, yours, exact_match, true)
|
19
|
+
extras = difference(yours, remote, exact_match)
|
20
|
+
both_lists = outdated_and_missing + extras
|
21
|
+
sorted_diff = sort_difference(both_lists).uniq { |item| item[:name] }
|
17
22
|
|
18
|
-
if
|
19
|
-
log_status_bottom '
|
23
|
+
if sorted_diff.empty?
|
24
|
+
log_status_bottom 'results', 'no differences were found',
|
25
|
+
:magenta, true
|
20
26
|
else
|
21
|
-
|
27
|
+
padded_length = pad_by(sorted_diff)
|
22
28
|
|
23
|
-
|
24
|
-
name
|
25
|
-
|
26
|
-
|
29
|
+
sorted_diff.each do |item|
|
30
|
+
name = sorted_diff.empty? ? item[:name] : item[:name].ljust(padded_length)
|
31
|
+
version = item[:version].empty? ? '' : "#{set_color('|',
|
32
|
+
:cyan)} #{item[:version]}"
|
27
33
|
|
28
|
-
|
29
|
-
|
30
|
-
color = :red
|
31
|
-
end
|
32
|
-
|
33
|
-
log_status_bottom status, name, color, true
|
34
|
+
log_status_bottom item[:status], "#{name} #{version}",
|
35
|
+
item[:color], true
|
34
36
|
end
|
35
|
-
|
36
|
-
log_results 'The latest version of orats may benefit you', 'Check github to see if the changes interest you'
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
|
41
|
-
item_diff = remote - local
|
42
|
-
item_diff_count = item_diff.size
|
40
|
+
private
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
def name_and_version_from_line(line)
|
43
|
+
line.split(',')
|
44
|
+
end
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
def pad_by(sorted_diff)
|
47
|
+
longest_role = sorted_diff.max_by { |s| s[:name].length }
|
48
|
+
longest_role[:name].length
|
49
|
+
end
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
51
|
+
def sort_difference(diff_list)
|
52
|
+
# custom sort order on the color key
|
53
|
+
diff_list.sort_by { |item| {red: 1,
|
54
|
+
yellow: 2,
|
55
|
+
green: 3}[item[:color]] }
|
58
56
|
end
|
59
57
|
|
60
|
-
def
|
61
|
-
|
58
|
+
def difference(remote, yours, exact_match, missing_and_outdated = false)
|
59
|
+
@diff_list = []
|
60
|
+
yours_as_string = yours.join
|
62
61
|
|
63
|
-
|
64
|
-
|
62
|
+
if missing_and_outdated
|
63
|
+
diff = remote - yours
|
65
64
|
|
66
|
-
|
67
|
-
|
65
|
+
diff.each do |line|
|
66
|
+
line_parts = name_and_version_from_line(line)
|
67
|
+
status = 'outdated'
|
68
|
+
color = :yellow
|
69
|
+
search_contents = exact_match ? yours : yours_as_string
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
log_results 'Everything appears to be in order', "No missing #{keyword} were found"
|
74
|
-
end
|
75
|
-
|
76
|
-
if extra_count > 0
|
77
|
-
log_results "#{extra_count} extra #{keyword} were detected:",
|
78
|
-
"No problem but remember to add them to future #{label}"
|
79
|
-
else
|
80
|
-
log_results "No extra #{keyword} were found:", "Extra #{keyword} are fine but you have none"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
71
|
+
unless search_contents.include?(line_parts[0])
|
72
|
+
status = 'missing'
|
73
|
+
color = :red
|
74
|
+
end
|
85
75
|
|
86
|
-
|
87
|
-
|
76
|
+
@diff_list.push({
|
77
|
+
color: color,
|
78
|
+
status: status,
|
79
|
+
name: line_parts[0],
|
80
|
+
version: line_parts[1] || ''
|
81
|
+
})
|
88
82
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
83
|
+
end
|
84
|
+
else
|
85
|
+
remote.each do |line|
|
86
|
+
unless yours.include?(line)
|
87
|
+
line_parts = name_and_version_from_line(line)
|
88
|
+
status = 'extra'
|
89
|
+
color = :green
|
90
|
+
|
91
|
+
@diff_list.push({
|
92
|
+
color: color,
|
93
|
+
status: status,
|
94
|
+
name: line_parts[0],
|
95
|
+
version: line_parts[1] || ''
|
96
|
+
})
|
97
|
+
end
|
93
98
|
end
|
94
99
|
end
|
95
100
|
|
96
|
-
|
101
|
+
@diff_list
|
97
102
|
end
|
98
103
|
end
|
99
104
|
end
|
@@ -10,75 +10,49 @@ module Orats
|
|
10
10
|
include Parse
|
11
11
|
include Compare
|
12
12
|
|
13
|
+
attr_accessor :diff_list
|
14
|
+
|
13
15
|
def initialize(target_path = '', options = {})
|
14
16
|
super
|
15
17
|
|
16
18
|
@remote_galaxyfile = galaxyfile url_to_string(@remote_paths[:galaxyfile])
|
19
|
+
@remote_playbook = playbook url_to_string(@remote_paths[:playbook])
|
17
20
|
@remote_hosts = hosts url_to_string(@remote_paths[:hosts])
|
18
21
|
@remote_inventory = inventory url_to_string(@remote_paths[:inventory])
|
19
|
-
@remote_playbook = playbook url_to_string(@remote_paths[:playbook])
|
20
|
-
|
21
|
-
@local_galaxyfile = galaxyfile file_to_string(@local_paths[:galaxyfile])
|
22
|
-
@local_hosts = hosts file_to_string(@local_paths[:hosts])
|
23
|
-
@local_inventory = inventory file_to_string(@local_paths[:inventory])
|
24
|
-
@local_playbook = playbook file_to_string(@local_paths[:playbook])
|
25
|
-
end
|
26
|
-
|
27
|
-
def init
|
28
|
-
remote_to_local_gem_versions
|
29
|
-
remote_to_local_galaxyfiles
|
30
|
-
remote_to_local 'hosts', 'groups', @remote_hosts, @local_hosts
|
31
|
-
remote_to_local 'inventory', 'variables', @remote_inventory, @local_inventory
|
32
|
-
remote_to_local 'playbook', 'roles', @remote_playbook, @local_playbook
|
33
|
-
|
34
|
-
local_to_user_hosts @options[:hosts] unless @options[:hosts].empty?
|
35
|
-
|
36
|
-
unless @options[:inventory].empty?
|
37
|
-
inventory_path = @options[:inventory]
|
38
|
-
|
39
|
-
if File.directory?(inventory_path)
|
40
|
-
hosts_path = File.join(inventory_path, 'hosts')
|
41
|
-
|
42
|
-
inventory_path = File.join(inventory_path,
|
43
|
-
'group_vars/all.yml')
|
44
22
|
|
45
|
-
|
46
|
-
|
23
|
+
galaxyfile_path = @options[:galaxyfile]
|
24
|
+
playbook_path = @options[:playbook]
|
25
|
+
hosts_path = @options[:hosts]
|
26
|
+
inventory_path = @options[:inventory]
|
47
27
|
|
48
|
-
|
28
|
+
if !@options[:inventory].empty? && File.directory?(@options[:inventory])
|
29
|
+
hosts_path = File.join(inventory_path, 'hosts')
|
30
|
+
inventory_path = File.join(inventory_path, 'group_vars/all.yml')
|
49
31
|
end
|
50
32
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if File.directory?(playbook_path)
|
55
|
-
playbook_path = File.join(playbook_path, 'site.yml')
|
56
|
-
|
57
|
-
local_to_user_playbook playbook_path
|
58
|
-
end
|
59
|
-
|
60
|
-
local_to_user_playbook playbook_path
|
33
|
+
if !@options[:playbook].empty? && File.directory?(@options[:playbook])
|
34
|
+
galaxyfile_path = File.join(playbook_path, 'Galaxyfile')
|
35
|
+
playbook_path = File.join(playbook_path, 'site.yml')
|
61
36
|
end
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
37
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
38
|
+
@your_galaxyfile = galaxyfile file_to_string (galaxyfile_path) unless galaxyfile_path.empty?
|
39
|
+
@your_playbook = playbook file_to_string(playbook_path) unless playbook_path.empty?
|
40
|
+
@your_hosts = hosts file_to_string(hosts_path) unless hosts_path.empty?
|
41
|
+
@your_inventory = inventory file_to_string(inventory_path) unless inventory_path.empty?
|
71
42
|
|
72
|
-
def local_to_user_inventory(path)
|
73
|
-
local_to_user('inventory', 'variables', path, @local_inventory) do
|
74
|
-
inventory file_to_string(path)
|
75
|
-
end
|
76
43
|
end
|
77
44
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
45
|
+
def init
|
46
|
+
remote_gem_vs_yours
|
47
|
+
|
48
|
+
remote_vs_yours('galaxyfile', @remote_galaxyfile,
|
49
|
+
@your_galaxyfile, false) unless @your_galaxyfile.nil?
|
50
|
+
remote_vs_yours('playbook', @remote_playbook,
|
51
|
+
@your_playbook, true) unless @your_playbook.nil?
|
52
|
+
remote_vs_yours('hosts', @remote_hosts,
|
53
|
+
@your_hosts, true) unless @your_hosts.nil?
|
54
|
+
remote_vs_yours('inventory', @remote_inventory,
|
55
|
+
@your_inventory, true) unless @your_inventory.nil?
|
82
56
|
end
|
83
57
|
end
|
84
58
|
end
|
@@ -37,8 +37,6 @@ module Orats
|
|
37
37
|
run "#{create_rsa_certificate(secrets_path,
|
38
38
|
'monit.pem', 'monit.pem')} && openssl gendh 512 >> #{secrets_path}/monit.pem"
|
39
39
|
|
40
|
-
install_role_dependencies unless @options[:skip_galaxy]
|
41
|
-
|
42
40
|
log_success
|
43
41
|
end
|
44
42
|
|
@@ -79,25 +77,6 @@ module Orats
|
|
79
77
|
"openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj '/C=US/ST=Foo/L=Bar/O=Baz/CN=qux.com' -keyout #{secrets_path}/#{keyout} -out #{secrets_path}/#{out}"
|
80
78
|
end
|
81
79
|
|
82
|
-
def install_role_dependencies
|
83
|
-
log_task 'Update ansible roles from the galaxy'
|
84
|
-
|
85
|
-
galaxy_install =
|
86
|
-
"ansible-galaxy install -r #{base_path}/#{Common::RELATIVE_PATHS[:galaxyfile]} --force"
|
87
|
-
|
88
|
-
galaxy_out = run(galaxy_install, capture: true)
|
89
|
-
|
90
|
-
if galaxy_out.include?('you do not have permission')
|
91
|
-
if @options[:sudo_password].empty?
|
92
|
-
sudo_galaxy_command = 'sudo'
|
93
|
-
else
|
94
|
-
sudo_galaxy_command = "echo #{@options[:sudo_password]} | sudo -S"
|
95
|
-
end
|
96
|
-
|
97
|
-
run("#{sudo_galaxy_command} #{galaxy_install}")
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
80
|
def log_success
|
102
81
|
log_status_top 'success', 'Everything has been setup successfully',
|
103
82
|
:cyan
|
@@ -11,10 +11,49 @@ module Orats
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def init
|
14
|
-
|
14
|
+
exit_if_updating_playbook
|
15
15
|
|
16
16
|
rails_template 'playbook'
|
17
17
|
custom_rails_template unless @options[:custom].empty?
|
18
|
+
|
19
|
+
galaxy_install
|
20
|
+
log_success
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def exit_if_updating_playbook
|
26
|
+
galaxyfile = File.join(@target_path, 'Galaxyfile')
|
27
|
+
|
28
|
+
if File.exist?(galaxyfile)
|
29
|
+
galaxy_install 'Update'
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def galaxy_install(git_commit_type='Add')
|
35
|
+
log_task "#{git_commit_type} ansible roles from the galaxy"
|
36
|
+
|
37
|
+
galaxy_install = "ansible-galaxy install -r #{@target_path}/Galaxyfile --roles-path #{@target_path}/roles --force"
|
38
|
+
|
39
|
+
run galaxy_install
|
40
|
+
|
41
|
+
git_commit "#{git_commit_type} galaxy installed roles"
|
42
|
+
end
|
43
|
+
|
44
|
+
def log_success
|
45
|
+
log_status_top 'success', 'Everything has been setup successfully',
|
46
|
+
:cyan
|
47
|
+
puts
|
48
|
+
log_status_bottom 'question', 'Are most of your apps similar?', :yellow, true
|
49
|
+
log_status_bottom 'answer', 'You only need to generate one playbook and you just did',
|
50
|
+
:white, true
|
51
|
+
log_status_bottom 'answer', 'Use the inventory in each project to customize certain things', :white
|
52
|
+
|
53
|
+
log_status_bottom 'question', 'Are you new to ansible?', :yellow, true
|
54
|
+
log_status_bottom 'answer',
|
55
|
+
'http://docs.ansible.com/intro_getting_started.html',
|
56
|
+
:white
|
18
57
|
end
|
19
58
|
end
|
20
59
|
end
|
data/lib/orats/commands/ui.rb
CHANGED
@@ -31,11 +31,6 @@ module Orats
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def log_remote_info(top_label, top_message, bottom_label, bottom_message)
|
34
|
-
log_status_top top_label, "#{top_message}:", :green
|
35
|
-
log_status_bottom bottom_label, bottom_message, :yellow
|
36
|
-
end
|
37
|
-
|
38
|
-
def log_local_info(top_label, top_message, bottom_label, bottom_message)
|
39
34
|
log_status_top top_label, "#{top_message}:", :blue
|
40
35
|
log_status_bottom bottom_label, bottom_message, :cyan
|
41
36
|
end
|
@@ -81,10 +81,17 @@ end
|
|
81
81
|
def add_main_playbook
|
82
82
|
log_task __method__
|
83
83
|
|
84
|
-
copy_from_local_gem 'site.yml'
|
84
|
+
copy_from_local_gem 'site.yml'
|
85
85
|
git_commit 'Add the main playbook'
|
86
86
|
end
|
87
87
|
|
88
|
+
def add_galaxyfile
|
89
|
+
log_task __method__
|
90
|
+
|
91
|
+
copy_from_local_gem 'Galaxyfile'
|
92
|
+
git_commit 'Add the Galaxyfile'
|
93
|
+
end
|
94
|
+
|
88
95
|
def remove_unused_files_from_git
|
89
96
|
log_task __method__
|
90
97
|
|
@@ -92,24 +99,11 @@ def remove_unused_files_from_git
|
|
92
99
|
git_commit 'Remove unused files'
|
93
100
|
end
|
94
101
|
|
95
|
-
def log_complete
|
96
|
-
puts
|
97
|
-
say_status 'success', "\e[1m\Everything has been setup successfully\e[0m", :cyan
|
98
|
-
puts
|
99
|
-
say_status 'question', 'Are most of your apps similar?', :yellow
|
100
|
-
say_status 'answer', 'You only need to generate one playbook and you just did', :white
|
101
|
-
say_status 'answer', 'Use the inventory in each project to customize certain things', :white
|
102
|
-
puts
|
103
|
-
say_status 'question', 'Are you new to ansible?', :yellow
|
104
|
-
say_status 'answer', 'http://docs.ansible.com/intro_getting_started.html', :white
|
105
|
-
puts
|
106
|
-
end
|
107
|
-
|
108
102
|
# ---
|
109
103
|
|
110
104
|
delete_generated_rails_code
|
111
105
|
add_playbook_directory
|
112
106
|
add_license
|
113
107
|
add_main_playbook
|
114
|
-
|
115
|
-
|
108
|
+
add_galaxyfile
|
109
|
+
remove_unused_files_from_git
|
data/lib/orats/version.rb
CHANGED
@@ -42,11 +42,43 @@ class TestCLI < Minitest::Test
|
|
42
42
|
assert_playbook
|
43
43
|
end
|
44
44
|
|
45
|
+
def test_playbook_update_roles
|
46
|
+
target_path = generate_app_name
|
47
|
+
|
48
|
+
assert_playbook target_path
|
49
|
+
assert_playbook target_path
|
50
|
+
end
|
51
|
+
|
45
52
|
def test_diff
|
46
|
-
|
53
|
+
assert_diff
|
47
54
|
|
48
|
-
|
49
|
-
|
55
|
+
out, err = capture_orats('diff')
|
56
|
+
|
57
|
+
assert_count out, 'gem', 1
|
58
|
+
assert_count out, 'missing', 0
|
59
|
+
assert_count out, 'outdated', 0
|
60
|
+
assert_count out, 'extra', 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_diff_with_differences
|
64
|
+
file_paths = assert_diff
|
65
|
+
|
66
|
+
hosts_path = "#{file_paths[0]}/hosts"
|
67
|
+
inventory_path = "#{file_paths[0]}/group_vars/all.yml"
|
68
|
+
galaxyfile_path = "#{file_paths[1]}/Galaxyfile"
|
69
|
+
site_path = "#{file_paths[1]}/site.yml"
|
70
|
+
|
71
|
+
gsub_file(hosts_path, '[cache]', '[something]')
|
72
|
+
gsub_file(inventory_path, 'postgres_user', 'hello_world')
|
73
|
+
gsub_file(galaxyfile_path, /nickjj.ruby,v.*$/, "nickjj.ruby,v0.1.2\nfoo")
|
74
|
+
gsub_file(site_path, 'nickjj.whenever', 'bar')
|
75
|
+
|
76
|
+
out, err = capture_orats('diff')
|
77
|
+
|
78
|
+
assert_count out, 'gem', 1
|
79
|
+
assert_count out, 'missing', 3
|
80
|
+
assert_count out, 'outdated', 1
|
81
|
+
assert_count out, 'extra', 4
|
50
82
|
end
|
51
83
|
|
52
84
|
def test_templates
|
@@ -62,7 +94,7 @@ class TestCLI < Minitest::Test
|
|
62
94
|
def assert_orats(command, match_regex, ansible: nil)
|
63
95
|
out, err = capture_orats(command)
|
64
96
|
|
65
|
-
assert_match /#{match_regex}/, out
|
97
|
+
assert_match /#{match_regex}/, out, err unless match_regex.empty?
|
66
98
|
|
67
99
|
assert_or_refute_ansible ansible if ansible
|
68
100
|
end
|
@@ -93,19 +125,33 @@ class TestCLI < Minitest::Test
|
|
93
125
|
|
94
126
|
def assert_inventory
|
95
127
|
@target_path = generate_app_name
|
96
|
-
@extra_flags = '--skip-galaxy'
|
97
128
|
|
98
129
|
assert_orats 'inventory', 'success'
|
130
|
+
assert_path "#{TEST_PATH}/#{@target_path}/inventory/hosts"
|
99
131
|
assert_ansible_yaml "#{TEST_PATH}/#{@target_path}/inventory/group_vars/all.yml"
|
100
132
|
end
|
101
133
|
|
102
|
-
def assert_playbook
|
103
|
-
@target_path =
|
134
|
+
def assert_playbook(target_path = generate_app_name)
|
135
|
+
@target_path = target_path
|
104
136
|
|
105
137
|
assert_orats 'playbook', 'success'
|
138
|
+
assert_path "#{TEST_PATH}/#{@target_path}/Galaxyfile"
|
106
139
|
assert_ansible_yaml "#{TEST_PATH}/#{@target_path}/site.yml"
|
107
140
|
end
|
108
141
|
|
142
|
+
def assert_diff
|
143
|
+
assert_inventory
|
144
|
+
inventory_path = "#{TEST_PATH}/#{@target_path}/inventory"
|
145
|
+
|
146
|
+
assert_playbook
|
147
|
+
playbook_path = "#{TEST_PATH}/#{@target_path}"
|
148
|
+
|
149
|
+
@target_path = ''
|
150
|
+
@extra_flags = "-i #{inventory_path} -p #{playbook_path}"
|
151
|
+
|
152
|
+
[inventory_path, playbook_path]
|
153
|
+
end
|
154
|
+
|
109
155
|
def assert_nuked(options = {})
|
110
156
|
out, err = capture_subprocess_io do
|
111
157
|
orats "nuke #{@target_path}", flags: options[:flags], answer: 'y'
|
@@ -115,6 +161,11 @@ class TestCLI < Minitest::Test
|
|
115
161
|
system "rm -rf #{TEST_PATH}"
|
116
162
|
end
|
117
163
|
|
164
|
+
def assert_count(input, regex, expected)
|
165
|
+
assert input.scan(regex).size == expected,
|
166
|
+
"Found #{input.scan(regex).size} matches for '#{regex}' but expected #{expected}"
|
167
|
+
end
|
168
|
+
|
118
169
|
def assert_in_file(file_path, match_regex)
|
119
170
|
file_contents = `cat #{file_path}`
|
120
171
|
assert_match /#{match_regex}/, file_contents
|
@@ -179,4 +230,11 @@ class TestCLI < Minitest::Test
|
|
179
230
|
puts '-'*80
|
180
231
|
puts
|
181
232
|
end
|
233
|
+
|
234
|
+
def gsub_file(file_path, replace, with)
|
235
|
+
IO.write(file_path, File.open(file_path) do |f|
|
236
|
+
f.read.gsub(replace, with)
|
237
|
+
end
|
238
|
+
)
|
239
|
+
end
|
182
240
|
end
|
data/test/test_helper.rb
CHANGED
@@ -15,8 +15,10 @@ module Orats
|
|
15
15
|
|
16
16
|
CREDENTIALS = "-l #{POSTGRES_LOCATION} -u #{POSTGRES_USERNAME} -p #{POSTGRES_PASSWORD} -n #{REDIS_LOCATION} -d #{REDIS_PASSWORD}"
|
17
17
|
|
18
|
+
INCLUDES_PATH = File.absolute_path('../../lib/orats/templates/includes',
|
19
|
+
__FILE__)
|
18
20
|
BINARY_PATH = File.absolute_path('../../bin/orats', __FILE__)
|
19
|
-
ORATS_NEW_FLAGS = "#{CREDENTIALS} -
|
21
|
+
ORATS_NEW_FLAGS = "#{CREDENTIALS} -S"
|
20
22
|
|
21
23
|
def orats(command, options = {})
|
22
24
|
cmd, app_name = command.split(' ')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Janetakis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|