ansible_spec 0.0.1.4 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
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