Pour le groupe de serveurs Linux défini avec Ansible, j'ai essayé de modifier (?) Ansible et serverspec afin de résoudre les problèmes suivants que j'ai rencontrés lors des tests avec serverspec.
serverspec-init
, il est difficile de préparer le code de test pour chaque répertoire avec le nom du serveur à tester.Veuillez vous y référer comme une édition d'introduction / débutant lorsque vous utilisez Ansible et serverspec en coopération.
Mettez en œuvre pour que vous puissiez:
Ansible Control Node
Ansible Managed Node
$ tree -aF /autotools
/autotools
|-- .ssh/
| `-- aws_key.pem #Clé privée SSH du nœud géré
|-- ansible/
| |-- ansible.cfg
| |-- group_vars/ #Répertoire de variables pour les groupes
| |-- host_vars/ #Répertoire des variables hôtes
| |-- inventory/ #Répertoire de placement d'inventaire pour Ansible
| `-- centos.yml # Playbook
`-- serverspec/
|-- .rspec
|-- Rakefile
|-- spec/
| |-- base/ #Répertoire de placement des manteaux d'essai pour le rôle de base
| | `-- sample_spec.rb #Code de test
| `-- spec_helper.rb
`-- spec_hosts/ #Répertoire de placement variable pour serverspec
Ansible
Tout d'abord, décidons project_name
avec une chaîne de caractères en anglais dans le but de gérer ce groupe de serveurs collectivement.
Ici, à titre d'exemple, utilisez project_name
comme ʻanken`.
ansible.cfg
Ici, spécifiez ʻansible.cfg à utiliser dans la variable d'environnement ʻANSIBLE_CONFIG
.
J'utilise le même nom d'hôte pour le développement de code, j'ai donc répertorié les arguments ssh ici.
$ export ANSIBLE_CONFIG=/autotools/ansible/ansible.cfg
/autotools/ansible/ansible.cfg
[defaults]
[ssh_connection]
ssh_args = -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
[privilege_escalation]
become = true
Placez la clé privée SSH utilisée pour SSH dans le nœud géré Ansible dans / autotools / .ssh
.
Le chemin d'accès de la clé est répertorié dans le fichier d'inventaire.
Placez le fichier d'inventaire ʻanken.inisous
/ autotools / ansible / inventaire /`.
Fondamentalement, c'est OK si vous écrivez selon la règle d'Ansible, mais comme il est utilisé dans le mécanisme de liaison avec serverspec, veuillez définir les trois indispensables suivants.
project_name
avec [all: vars]
, ʻansible_password
et ʻansible_ssh_private_key_file`, respectivement. Définissez le mot de passe ou la clé SSH. (Le mot de passe et la clé SSH écrits ici sont également utilisés dans serverspec via le fichier de variables décrit plus loin.)/autotools/ansible/inventory/anken.ini
[anken]
prod_foobar1 ansible_host=xx.xx.xx.xx
dev_foobar1 ansible_host=yy.yy.yy.yy
[anken:vars]
ansible_user=centos
ansible_ssh_private_key_file=~/.ssh/aws_key.pem
[all:vars]
project_name=anken
Ansible est exécuté pour l'IP ou le nom de ʻansible_host`.
ʻInventory_hostname (où
prod_foobar1
dev_foobar2` est spécifié dans l'exemple) ne doit pas nécessairement correspondre au nom d'hôte réel du nœud.
Playbook
L'exemple de playbook utilisé dans cet exemple d'implémentation est le suivant.
name: Configure for serverspec at localhost
renvoie le fichier de variables utilisé par serverspec.
centos.yml
---
- name: Playbook for centos7 managed node
hosts: all
gather_facts: true
tasks:
- name: Create group
group:
name: "{{ item.name }}"
gid: "{{ item.gid }}"
loop: "{{ group }}"
tags: group
- name: Create User
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
group: "{{ item.group }}"
groups: "{{ item.groups }}"
home: "{{ item.home }}"
shell: "{{ item.shell }}"
loop: "{{ user }}"
tags: user
- name: System service
systemd:
name: "{{ item.name }}"
enabled: "{{ item.enabled }}"
state: "{{ item.state }}"
loop: "{{ service }}"
tags: service
- name: Configure for serverspec at localhost
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Dump hostvars for serverspec
copy:
content: "{{ hostvars | to_nice_yaml }}"
dest: "../serverspec/spec_hosts/{{ project_name }}.yml"
tags: serverspec
Placez les variables communes au projet dans / autotools / ansible / group_vars / # {project_name} .yml
. Si vous souhaitez spécifier une variable différente uniquement pour un nom_hôte_inventaire spécifique, placez-la dans / autotools / ansible / host_vars / # {nom_inventaire} .yml
.
Dans le fichier de variables, spécifiez le rôle à utiliser lors du test avec serverspec avec serverspec_role
.
/autotools/ansible/group_vars/anken.yml
serverspec_role:
- base
group:
- name: unyo
gid: 1101
- name: infra
gid: 1102
- name: app
gid: 1103
user:
- name: user1
uid: 2001
group: customer
groups: [ unyo, infra]
home: /home/user1
shell: /bin/bash
- name: user2
uid: 2002
group: customer
groups: [ app ]
home: /home/user2
shell: /bin/bash
- name: user3
uid: 2003
group: customer
groups: [ app, infra ]
home: /home/user3
shell: /bin/bash
service:
- name: chronyd.service
enabled: false
state: stopped
- name: rsyncd.service
enabled: true
state: started
Ici, je vais le limiter au nœud prod_foobar
et écraser certaines variables.
/autotools/ansible/group_vars/prod_foobar.yml
group:
- name: unyo
gid: 2101
- name: infra
gid: 2102
- name: app
gid: 2103
Après avoir organisé les fichiers nécessaires, cela devrait ressembler à ceci.
$ tree /autotools/ansible -aF
/autotools/ansible
|-- ansible.cfg
|-- centos.yml
|-- group_vars/
| `-- anken.yml
|-- host_vars/
| `-- prod_foobar1
`-- inventory/
`-- anken.ini
Exécutez le playbook centos.yml avec le fichier d'inventaire comme indiqué ci-dessous.
$ cd /autotools/ansible
$ ansible -i ./inventory/anken centos.yml
serverspec
Après avoir exécuté Ansible, la structure des répertoires / fichiers du côté de la spécification de serveur devrait ressembler à ceci.
# tree /autotools/serverspec -aF
/autotools/serverspec
|-- .rspec
|-- Rakefile
|-- spec/
| |-- base/
| | `-- sample_spec.rb
| `-- spec_helper.rb
`-- spec_hosts/
`-- anken.yml #Fichier variable généré par Ansible
L'ordre est différent, mais la commande d'exécution de serverspec est la suivante. Il s'agit d'une image de transmission du nom de fichier variable (généré par Ansible) utilisé dans serverspec à la commande rake en tant qu'argument.
$ rake spec anken -T
rake spec # Run spec to all hosts
rake spec:dev_foobar1 # Run spec to dev_foobar1
rake spec:prod_foobar1 # Run spec to prod_foobar1
$ rake spec anken
Rakefile
Il y a quelques changements par rapport au standard Rakefile
créé par serverspec-init
.
/autotools/serverspec/Rakefile
require 'rake'
require 'rspec/core/rake_task'
require 'yaml'
#Lire le fichier de variables
project_name = ARGV[1]
hosts = YAML.load_file("./spec_hosts/#{project_name}.yml")
desc "Run spec to all hosts"
task :spec => 'spec:all'
namespace :spec do
task :all => hosts.keys.map {|key| 'spec:' + key }
hosts.keys.each do |key|
desc "Run spec to #{key}"
RSpec::Core::RakeTask.new(key.to_sym) do |t|
ENV['INVENTORY_HOST'] = key
ENV['PROJECT_NAME'] = project_name
# serverspec_Sous un répertoire portant le même nom que le rôle*_spec.Lire le fichier rb
t.pattern = 'spec/{' + hosts[key]['serverspec_role'].join(',') + '}/*_spec.rb'
t.fail_on_error = false
end
end
end
#Forger l'argument de la commande rake comme une tâche vide
ARGV.slice(1,ARGV.size).each{|v| task v.to_sym do; end}
Je l'ai utilisé comme référence ci-dessous. Merci beaucoup.
Référence: Écrire un traitement de type argument ordinaire dans la tâche Rake https://qiita.com/nao58/items/aa50514d97f05eb8d128
Référence: officiel Comment utiliser les propriétés spécifiques à l'hôte https://serverspec.org/advanced_tips.html
spec_helper.rb
Cela change également certaines fonctions de l'état initial spec_helper.rb
.
/autotools/serverspec/spec/spec_helper.rb
require 'serverspec'
require 'pathname'
require 'net/ssh'
require 'yaml'
#Lire le fichier yml variable
key = ENV['INVENTORY_HOST']
project_name = ENV['PROJECT_NAME']
properties = YAML.load_file("./spec_hosts/#{project_name}.yml")
set_property properties["#{key}"]
set :backend, :ssh
set :path, '/sbin:/usr/sbin:$PATH'
#partie exécution ssh
RSpec.configure do |c|
c.before :all do
#Extraire l'hôte, l'utilisateur, le mot de passe ou la clé utilisé dans Ansible à partir du fichier de variable lu
set :host, property['ansible_host']
options = Net::SSH::Config.for(c.host)
options[:user] = property['ansible_user']
if property['ansible_password']
options[:password] = property['ansible_password']
else
options[:keys] = [ property['ansible_ssh_private_key_file'] ]
end
options[:user_known_hosts_file] = '/dev/null'
set :ssh_options, options
end
end
Ce spec_helper.rb
ne prend pas en charge WinRM car il est set: backend ,: ssh
. Cependant, comme vous pouvez tout écrire en Ruby, il ne devrait pas être difficile de prendre en charge Windows.
Ceci est un échantillon.
Comme écrit dans spec_helper.rb
,property ['xxx']
peut être utilisé pour récupérer une variable d'un fichier de variable et la réutiliser.
/autotools/serverspec/spec/base/
# frozen_string_literal: true
require 'spec_helper'
puts "\nRun serverspec to #{property['inventory_hostname']}"
property['group'].each do |attr|
describe group(attr['name']) do
it { should exist }
it { should have_gid attr['gid'] }
end
end
property['user'].each do |attr|
describe user(attr['name']) do
it { should exist }
it { should have_uid attr['uid'] }
it { should belong_to_group attr['group'] }
end
end
property['service'].each do |attr|
describe service(attr['name']) do
attr['enabled'] ? it { should be_enabled } : it { should_not be_enabled }
attr['state'] == 'started' ? it { should be_running } : it { should_not be_running }
end
end
Encore une fois, exécutez la commande rake spec avec le nom de fichier de variable généré par Ansible comme argument, comme indiqué ci-dessous. Il est également possible d'exécuter des tests pour chaque unité.
$ rake spec anken
$
$ rake spec anken -T #Commande pour afficher la liste des tâches
rake spec # Run spec to all hosts
rake spec:dev_foobar1 # Run spec to dev_foobar1
rake spec:prod_foobar1 # Run spec to prod_foobar1
$
$ rake spec:dev_foobar1 anken
Avec Ansible et serverspec, nous avons pu unifier les fichiers variables et les fichiers d'événements, qui ont tendance à être gérés en double. De plus, j'ai pu gérer et exécuter le code de test rôle par rôle en me référant à la méthode décrite dans la formule serverspec.
Étant donné que serverspec est un outil assez coloré, c'est difficile pour les personnes qui ne touchent généralement pas Ruby, mais une fois que vous vous y êtes habitué, il est bon que divers processus soient faciles à écrire.
Il est publié ci-dessous. https://github.com/kentarok/autotools
Recommended Posts