ansible_spec 0.0.1.4 → 0.1

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: 72fba25ed4abe4c3996c35f674c6296a5b71ac74
4
- data.tar.gz: 6f0a5120c52fd85162bf721022009382d9cd9f23
3
+ metadata.gz: 9786a12ddd76b367acc6a746e7933d3e05d8e8fc
4
+ data.tar.gz: 62c75b1aa15c19784b67a5250a5ac3d3e48edddd
5
5
  SHA512:
6
- metadata.gz: f6f845d822b12278605e8ca7479b368ac6cf30c25826b23a17c7b079758db17a13e6419e3d04ff2f53ab82265d2841991343a3e77d8057760576ae3f23ad2a31
7
- data.tar.gz: 22ca53f5baf32f1311ccfb9fb6ee69e3080f12a2b5e8b94fa885af96f3c674dfccb0bc8d994a2057b1c1f270de29f3ec19a01a39bc5c0e4756792bbbf5117c70
6
+ metadata.gz: 85c49993d9dcf8d4b7a731e9c7b7dce822c9a2574bb3707d1c174aea42aa8c4272495d0773c4e9158802e51455f730a2eb33e40e201452e5be0f1d6fc75f0a10
7
+ data.tar.gz: 06290b9e0c60a0f54071f8e0f393c1de390b8f5713e1de02e4085085fb0bc1e0241aa38981e6b7259c0ceb2a4e07052fef3be59ebdc4f7cb613cc2af2cdb8f2f
data/.travis.yml CHANGED
@@ -4,5 +4,6 @@ rvm:
4
4
  - 2.0.0
5
5
  - 2.1.0
6
6
  - 2.1.1
7
+ - 2.2.0
7
8
  script:
8
9
  - rspec spec
data/README.md CHANGED
@@ -2,19 +2,38 @@
2
2
  [![Gem Version](https://badge.fury.io/rb/ansible_spec.svg)](http://badge.fury.io/rb/ansible_spec)
3
3
  [![Build Status](https://travis-ci.org/volanja/ansible_spec.svg?branch=master)](https://travis-ci.org/volanja/ansible_spec)
4
4
 
5
- This is Severspec template for Run test Multi Role and Multi Host with Ansible
6
- Create template (Rakefile and spec/spec_hepler.rb)
7
- Serverspec template use Ansible InventoryFile and site.yml
5
+ This gem is Ansible Config Parser for Serverspec.
6
+ Serverspec RakeTask uses Ansible Config(InventoryFile and Playbook).
7
+ Support Run Multi Role and Multi Host of Ansible.
8
+
9
+ This gem created template file until v0.0.1.4,
10
+ But it was modularized on v0.1. Because module is easy to unit-test and Rakefile is simple.
11
+
12
+ If you want old release that can create template, use `gem install ansible_spec -v 0.0.1.4`
13
+ But I can't support(Bug fix, Add feature) old release.
14
+
15
+ ## New feature at v0.1
16
+
17
+ - Support Serverspec v2
18
+ - Simplification Rakefile and Modularization. Because of Improvement of testability.
19
+ - Support InventoryParameters
20
+ - ansible_ssh_port
21
+ - ansible_ssh_user
22
+ - ansible_ssh_host
23
+ - ansible_ssh_private_key_file
24
+ - Support [hostlist expressions](http://docs.ansible.com/intro_inventory.html#hosts-and-groups)
25
+ - Support DynamicInventory
8
26
 
9
27
  ## Installation
10
28
 
11
29
  install it yourself as:
12
30
 
13
- $ gem install ansible_spec
31
+ ```
32
+ $ gem install ansible_spec
33
+ ```
14
34
 
15
35
  ## Usage
16
-
17
- ### Create file Serverspec
36
+ ### Create Rakafile & spec/spec_helper.rb
18
37
 
19
38
  ```
20
39
  $ ansiblespec-init
@@ -24,6 +43,14 @@ $ ansiblespec-init
24
43
  create .ansiblespec
25
44
  ```
26
45
 
46
+ ### VersionUp from v0.0.1.4 to v0.1
47
+
48
+ ```
49
+ $ rm Rakefile
50
+ $ rm spec/spec_helper.md
51
+ $ ansiblespec-init
52
+ ```
53
+
27
54
  ### Change .ansiblespec(v0.0.1.3)
28
55
  If `.ansiblespec` is exist, use variables(playbook and inventory).
29
56
  So, If you don't use `site.yml` and `hosts`, you change this file.
@@ -65,20 +92,62 @@ sample is [here](https://github.com/volanja/ansible-sample-tdd)
65
92
  ```
66
93
 
67
94
  ### Serverspec with Ansible
68
- Serverspec use this file. (Rakefile understand Notation of Ansible.)
69
-
70
- * hosts
71
- hosts can use [group_name]
95
+ Serverspec use Ansible file. (Rakefile understand Notation of Ansible.)
96
+
97
+ * Inventory file
98
+ Inventory file can sue this:
99
+ - InventoryParameters
100
+ - ansible_ssh_port
101
+ - ansible_ssh_user
102
+ - ansible_ssh_private_key
103
+ - ansible_ssh_host
104
+ - define hosts as expressions. `host-[1:3]` would expand into `host-1`,`host-2`,`host-3`
105
+ - Group Children
106
+ - [DynamicInventory](http://docs.ansible.com/intro_dynamic_inventory.html)
72
107
 
73
108
  ```hosts
74
109
  [server]
75
- 192.168.0.103
76
- 192.168.0.104
110
+ # skip line(comment)
111
+ # normal
112
+ 192.168.0.1
113
+ # use port 5309
114
+ 192.168.0.3:5309
115
+ # use port 22
116
+ 192.168.0.2 ansible_ssh_port=22
117
+ # use Private-key ~/.ssh/id_rsa
118
+ 192.168.0.4 ansible_ssh_private_key_file=~/.ssh/id_rsa
119
+ # use user `git`
120
+ 192.168.0.5 ansible_ssh_user=git
121
+ # use port 5555 & host 192.168.1.50
122
+ jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50
123
+
124
+ [web]
125
+ # www1.example.com to www99.example.com
126
+ www[1:99].example.com
127
+ # www01.example.com to www99.example.com
128
+ www[01:99].example.com
129
+
130
+ [databases]
131
+ # db-a.example.com to db-z.example.com
132
+ db-[a:z].example.com
133
+ # db-A.example.com to db-Z.example.com
134
+ db-[A:Z].example.com
135
+
136
+ # Multi Group. use server & databases
137
+ [parent:children]
138
+ server
139
+ databases
140
+ ```
77
141
 
142
+ or DynamicInventory(need execute permission)
143
+
144
+ ```example that DynamicInventory
145
+ #!/bin/bash
146
+ echo '{"databases": {"hosts": ["host1.example.com", "host2.example.com"],"vars":{"a": true}}}'
78
147
  ```
79
148
 
80
- * site.yml
81
- site.yml can use ```include```
149
+ * playbook
150
+ playbook can use `include`
82
151
 
83
152
  ```site.yml
84
153
  - name: Ansible-Sample-TDD
@@ -86,12 +155,18 @@ site.yml can use ```include```
86
155
  user: root
87
156
  roles:
88
157
  - nginx
158
+ - name: Ansible-Sample-TDD2
159
+ hosts: parent
160
+ user: root
161
+ roles:
162
+ - nginx
89
163
  ```
90
164
 
91
- ## Run Test
165
+ ## Run Test(Sample)
92
166
  ```
93
167
  $ rake -T
94
- rake serverspec:Ansible-Sample-TDD # Run serverspec for Ansible-Sample-TDD
168
+ rake serverspec:Ansible-Sample-TDD # Run serverspec for Ansible-Sample-TDD
169
+ rake serverspec:Ansible-Sample-TDD2 # Run serverspec for Ansible-Sample-TDD2
95
170
 
96
171
  $ rake serverspec:Ansible-Sample-TDD
97
172
  Run serverspec for Ansible-Sample-TDD to 192.168.0.103
data/ansible_spec.gemspec CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |gem|
8
8
  gem.version = AnsibleSpec::VERSION
9
9
  gem.authors = ["volanja"]
10
10
  gem.email = ["volaaanja@gmail.com"]
11
- gem.description = %q{This is Severspec template for Run test Multi Role and Multi Host with Ansible}
12
- gem.summary = %q{This is Severspec template for Run test Multi Role and Multi Host with Ansbile}
13
- gem.homepage = "https://github.com/volanja"
11
+ gem.description = %q{Ansible Config Parser for Serverspec. Run test Multi Role and Multi Host by Ansible Configuration}
12
+ gem.summary = %q{Ansible Config Parser for Serverspec. Run test Multi Role and Multi Host by Ansible Configuration}
13
+ gem.homepage = "https://github.com/volanja/ansible_spec"
14
14
  gem.license = "MIT"
15
15
 
16
16
  gem.files = `git ls-files`.split($/)
@@ -20,7 +20,11 @@ Gem::Specification.new do |gem|
20
20
 
21
21
  gem.add_development_dependency "bundler", "~> 1.3"
22
22
  gem.add_development_dependency "rake"
23
+ gem.add_development_dependency "diff-lcs"
24
+ gem.add_development_dependency "simplecov"
23
25
 
24
- gem.add_runtime_dependency "serverspec", ">= 0.13.5"
26
+ gem.add_runtime_dependency "serverspec", ">= 2.0.0"
27
+ gem.add_runtime_dependency "hostlist_expression"
28
+ gem.add_runtime_dependency "oj"
25
29
 
26
30
  end
data/lib/ansible_spec.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "ansible_spec/version"
2
+ require "ansible_spec/load_ansible"
2
3
  require "fileutils"
3
4
 
4
5
  # Reference
@@ -16,41 +17,7 @@ module AnsibleSpec
16
17
 
17
18
 
18
19
  def self.safe_create_spec_helper
19
- content = <<'EOF'
20
- require 'serverspec'
21
- require 'pathname'
22
- require 'net/ssh'
23
-
24
- include SpecInfra::Helper::Ssh
25
- include SpecInfra::Helper::DetectOS
26
-
27
- RSpec.configure do |c|
28
- if ENV['ASK_SUDO_PASSWORD']
29
- require 'highline/import'
30
- c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
31
- else
32
- c.sudo_password = ENV['SUDO_PASSWORD']
33
- end
34
- c.before :all do
35
- block = self.class.metadata[:example_group_block]
36
- if RUBY_VERSION.start_with?('1.8')
37
- file = block.to_s.match(/.*@(.*):[0-9]+>/)[1]
38
- else
39
- file = block.source_location.first
40
- end
41
- host = ENV['TARGET_HOST']
42
- if c.host != host
43
- c.ssh.close if c.ssh
44
- c.host = host
45
- options = Net::SSH::Config.for(c.host)
46
- user = ENV['TARGET_USER']
47
- options[:keys] = ENV['TARGET_PRIVATE_KEY']
48
- c.ssh = Net::SSH.start(host, user, options)
49
- end
50
- end
51
- end
52
-
53
- EOF
20
+ content = File.open(File.dirname(__FILE__) + "/../lib/src/spec/spec_helper.rb").read
54
21
  safe_mkdir("spec")
55
22
  safe_touch("spec/spec_helper.rb")
56
23
  File.open("spec/spec_helper.rb", 'w') do |f|
@@ -60,110 +27,15 @@ EOF
60
27
  end
61
28
 
62
29
  def self.safe_create_rakefile
63
- content = <<'EOF'
64
- require 'rake'
65
- require 'rspec/core/rake_task'
66
- require 'yaml'
67
-
68
- # param: none
69
- # return: @playbook, @inventoryfile
70
- def load_ansiblespec()
71
- f = '.ansiblespec'
72
- if File.exist?(f)
73
- y = YAML.load_file(f)
74
- @playbook = y[0]['playbook']
75
- @inventoryfile = y[0]['inventory']
76
- else
77
- @playbook = 'site.yml'
78
- @inventoryfile = 'hosts'
79
- end
80
- if File.exist?(@playbook) == false
81
- puts 'Error: ' + @playbook + ' is not Found. create site.yml or /.ansiblespec See https://github.com/volanja/ansible_spec'
82
- exit 1
83
- elsif File.exist?(@inventoryfile) == false
84
- puts 'Error: ' + @inventoryfile + ' is not Found. create hosts or /.ansiblespec See https://github.com/volanja/ansible_spec'
85
- exit 1
86
- end
87
- end
88
-
89
- # param: inventory file of Ansible
90
- # return: Hash {"active_group_name" => ["192.168.0.1","192.168.0.2"]}
91
- def load_host(file)
92
- hosts = File.open(file).read
93
- active_group = Hash.new
94
- active_group_name = ''
95
- hosts.each_line{|line|
96
- line = line.chomp
97
- next if line.start_with?('#')
98
- if line.start_with?('[') && line.end_with?(']')
99
- active_group_name = line.gsub('[','').gsub(']','')
100
- active_group["#{active_group_name}"] = Array.new
101
- elsif active_group_name.empty? == false
102
- next if line.empty? == true
103
- active_group["#{active_group_name}"] << line
104
- end
105
- }
106
- return active_group
107
- end
108
-
109
- # main
110
- load_ansiblespec
111
- load_file = YAML.load_file(@playbook)
112
-
113
- # e.g. comment-out
114
- if load_file === false
115
- puts 'Error: No data in site.yml'
116
- exit
117
- end
118
-
119
- properties = Array.new
120
- load_file.each do |site|
121
- if site.has_key?("include")
122
- properties.push YAML.load_file(site["include"])[0]
123
- else
124
- properties.push site
125
- end
126
- end
127
-
128
-
129
- #load inventry file
130
- hosts = load_host(@inventoryfile)
131
- properties.each do |var|
132
- if hosts.has_key?("#{var["hosts"]}")
133
- var["hosts"] = hosts["#{var["hosts"]}"]
134
- end
135
- end
136
-
137
- namespace :serverspec do
138
- properties.each do |var|
139
- var["hosts"].each do |host|
140
- desc "Run serverspec for #{var["name"]}"
141
- RSpec::Core::RakeTask.new(var["name"].to_sym) do |t|
142
- puts "Run serverspec for #{var["name"]} to #{host}"
143
- ENV['TARGET_HOST'] = host
144
- ENV['TARGET_PRIVATE_KEY'] = '~/.ssh/id_rsa'
145
- ENV['TARGET_USER'] = var["user"]
146
- t.pattern = 'roles/{' + var["roles"].join(',') + '}/spec/*_spec.rb'
147
- end
148
- end
149
- end
150
- end
151
-
152
- EOF
30
+ content = File.open(File.dirname(__FILE__) + "/../lib/src/Rakefile").read
153
31
  safe_touch("Rakefile")
154
32
  File.open("Rakefile", 'w') do |f|
155
33
  f.puts content
156
34
  end
157
-
158
35
  end
159
36
 
160
37
  def self.safe_create_ansiblespec
161
- content = <<'EOF'
162
- ---
163
- -
164
- playbook: site.yml
165
- inventory: hosts
166
- EOF
38
+ content = File.open(File.dirname(__FILE__) + "/../lib/src/.ansiblespec").read
167
39
  safe_touch(".ansiblespec")
168
40
  File.open(".ansiblespec", 'w') do |f|
169
41
  f.puts content
@@ -0,0 +1,179 @@
1
+ require 'hostlist_expression'
2
+ require 'oj'
3
+
4
+ module AnsibleSpec
5
+ # param: inventory file of Ansible
6
+ # return: Hash {"group" => ["192.168.0.1","192.168.0.2"]}
7
+ # return: Hash {"group" => [{"name" => "192.168.0.1","uri" => "192.168.0.1", "port" => 22},...]}
8
+ def self.load_targets(file)
9
+ if File.executable?(file)
10
+ return get_dynamic_inventory(file)
11
+ end
12
+ f = File.open(file).read
13
+ res = Hash.new
14
+ group = ''
15
+ f.each_line{|line|
16
+ line = line.chomp
17
+ # skip
18
+ next if line.start_with?('#') #comment
19
+ next if line.empty? == true #null
20
+
21
+ # get group
22
+ if line.start_with?('[') && line.end_with?(']')
23
+ group = line.gsub('[','').gsub(']','')
24
+ res["#{group}"] = Array.new
25
+ next
26
+ end
27
+
28
+ #get host
29
+ if group.empty? == false
30
+ host = Hash.new
31
+ # 1つのみ、かつ:を含まない場合
32
+ if line.split.count == 1 && !line.include?(":")
33
+ # 192.168.0.1
34
+ res["#{group}"] << line
35
+ next
36
+ elsif line.split.count == 1 && line.include?("[") && line.include?("]")
37
+ # www[01:50].example.com
38
+ # db-[a:f].example.com
39
+ hostlist_expression(line,":").each{|h|
40
+ res["#{group}"] << h
41
+ }
42
+ next
43
+ else
44
+ res["#{group}"] << get_inventory_param(line)
45
+ next
46
+ end
47
+ end
48
+ }
49
+
50
+ # parse children [group:children]
51
+ search = Regexp.new(":children".to_s)
52
+ res.keys.each{|k|
53
+ unless (k =~ search).nil?
54
+ # get group parent & merge parent
55
+ res.merge!(get_parent(res,search,k))
56
+ # delete group children
57
+ if res.has_key?("#{k}") && res.has_key?("#{k.gsub(search,'')}")
58
+ res.delete("#{k}")
59
+ end
60
+ end
61
+ }
62
+ return res
63
+ end
64
+
65
+ # param hash {"server"=>["192.168.0.103"], "databases"=>["192.168.0.104"], "pg:children"=>["server", "databases"]}
66
+ # param search ":children"
67
+ # param k "pg:children"
68
+ # return {"server"=>["192.168.0.103"], "databases"=>["192.168.0.104"], "pg"=>["192.168.0.103", "192.168.0.104"]}
69
+ def self.get_parent(hash,search,k)
70
+ k_parent = k.gsub(search,'')
71
+ arry = Array.new
72
+ hash["#{k}"].each{|group|
73
+ arry = arry + hash["#{group}"]
74
+ }
75
+ h = Hash.new
76
+ h["#{k_parent}"] = arry
77
+ return h
78
+ end
79
+
80
+ # param filename
81
+ # {"databases":{"hosts":["aaa.com","bbb.com"],"vars":{"a":true}}}
82
+ # return {"databases"=>["aaa.com", "bbb.com"]}
83
+ def self.get_dynamic_inventory(file)
84
+ so, se, st = Open3.capture3("./#{file}")
85
+ res = Hash.new
86
+ Oj.load(so.to_s).each{|k,v|
87
+ res["#{k.to_s}"] = v['hosts']
88
+ }
89
+ return res
90
+ end
91
+
92
+ # param ansible_ssh_port=22
93
+ # return: hash
94
+ def self.get_inventory_param(line)
95
+ host = Hash.new
96
+ # 初期値
97
+ host['name'] = line
98
+ host['port'] = 22
99
+ if line.include?(":") # 192.168.0.1:22
100
+ host['uri'] = line.split(":")[0]
101
+ host['port'] = line.split(":")[1].to_i
102
+ return host
103
+ end
104
+ # 192.168.0.1 ansible_ssh_port=22
105
+ line.split.each{|v|
106
+ unless v.include?("=")
107
+ host['uri'] = v
108
+ else
109
+ key,value = v.split("=")
110
+ host['port'] = value.to_i if key == "ansible_ssh_port"
111
+ host['private_key'] = value if key == "ansible_ssh_private_key_file"
112
+ host['user'] = value if key == "ansible_ssh_user"
113
+ host['uri'] = value if key == "ansible_ssh_host"
114
+ end
115
+ }
116
+ return host
117
+ end
118
+
119
+ # param: none
120
+ # return: playbook, inventoryfile
121
+ def self.load_ansiblespec()
122
+ f = '.ansiblespec'
123
+ if File.exist?(f)
124
+ y = YAML.load_file(f)
125
+ playbook = y[0]['playbook']
126
+ inventoryfile = y[0]['inventory']
127
+ else
128
+ playbook = 'site.yml'
129
+ inventoryfile = 'hosts'
130
+ end
131
+ if File.exist?(playbook) == false
132
+ puts 'Error: ' + playbook + ' is not Found. create site.yml or ./.ansiblespec See https://github.com/volanja/ansible_spec'
133
+ exit 1
134
+ elsif File.exist?(inventoryfile) == false
135
+ puts 'Error: ' + inventoryfile + ' is not Found. create hosts or ./.ansiblespec See https://github.com/volanja/ansible_spec'
136
+ exit 1
137
+ end
138
+ return playbook, inventoryfile
139
+ end
140
+
141
+ # param: playbook
142
+ # return: json
143
+ # {"name"=>"Ansible-Sample-TDD", "hosts"=>"server", "user"=>"root", "roles"=>["nginx", "mariadb"]}
144
+ def self.load_playbook(f)
145
+ playbook = YAML.load_file(f)
146
+
147
+ # e.g. comment-out
148
+ if playbook === false
149
+ puts 'Error: No data in site.yml'
150
+ exit
151
+ end
152
+ properties = Array.new
153
+ playbook.each do |site|
154
+ if site.has_key?("include")
155
+ properties.push YAML.load_file(site["include"])[0]
156
+ else
157
+ properties.push site
158
+ end
159
+ end
160
+ return properties
161
+ end
162
+
163
+ # return: json
164
+ # {"name"=>"Ansible-Sample-TDD", "hosts"=>["192.168.0.103"], "user"=>"root", "roles"=>["nginx", "mariadb"]}
165
+ def self.get_properties()
166
+ playbook, inventoryfile = load_ansiblespec
167
+
168
+ #load inventry file
169
+ # inventory fileとplaybookのhostsをマッピングする。
170
+ hosts = load_targets(inventoryfile)
171
+ properties = load_playbook(playbook)
172
+ properties.each do |var|
173
+ if hosts.has_key?("#{var["hosts"]}")
174
+ var["hosts"] = hosts["#{var["hosts"]}"]
175
+ end
176
+ end
177
+ return properties
178
+ end
179
+ end