Skip to content

Commit

Permalink
Merge branch 'release/0.15'
Browse files Browse the repository at this point in the history
  • Loading branch information
TizianoPerrucci committed Sep 29, 2015
2 parents 9ddfb67 + f794e43 commit 068c593
Show file tree
Hide file tree
Showing 13 changed files with 354 additions and 15 deletions.
16 changes: 16 additions & 0 deletions HISTORY.rst
@@ -1,6 +1,22 @@
Release History
---------------

0.15 (2015-09-29)
+++++++++++++++++

**Improvements**

- Adds script that can generate dynamically an Ansible inventory based on the instances connected to an AWS ELB.
- Adds HashiCorp Vault Ansible lookup plugin.
- Adds HashiCorp File Ansible module.
- Adds bundled task: mongodb_3.
- Updates Ngnix example and improves Monit task.
- Updates to Ansible 1.9.3.

**Bugfixes**

- Changed state for UFW from 'disabled' to 'reset' to avoid old and new rules to be merged.

0.14 (2015-09-04)
+++++++++++++++++

Expand Down
13 changes: 13 additions & 0 deletions examples/components/client.yml
Expand Up @@ -31,6 +31,19 @@
sudo: yes
tags: client

- name: Client | Copy SSL Certificates
copy: src={{ssl_dir_path}}/{{item}} dest={{ssl_install_path}}/{{item}}
with_items: ssl_files
sudo: yes
tags:
- client
- update

- name: Client | Generate nginx dhparam.pem if not exists
command: openssl dhparam -out {{ssl_install_path}}/dhparam.pem 4096 creates={{ssl_install_path}}/dhparam.pem
sudo: yes
tags: client

- name: Client | Copy Nginx configuration
template: src={{root_dir}}/components/templates/client/nginx.conf.j2 dest=/etc/nginx/sites-available/example.com backup=yes
sudo: yes
Expand Down
6 changes: 4 additions & 2 deletions examples/components/templates/client/nginx.conf.j2
Expand Up @@ -294,9 +294,11 @@ server {

# Protect against the BEAST attack by preferring RC4-SHA when using SSLv3 and TLS protocols.
# Note that TLSv1.1 and TLSv1.2 are immune to the beast attack but only work with OpenSSL v1.0.1 and higher and has limited client support.
# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers RC4:HIGH:!aNULL:!MD5;
# Follow config per https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
# ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL:!eNULL:!MEDIUM:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED";
# ssl_prefer_server_ciphers on;
# ssl_dhparam /etc/nginx/dhparam.pem;


# Optimize SSL by caching session parameters for 10 minutes. This cuts down on the number of expensive SSL handshakes.
Expand Down
2 changes: 1 addition & 1 deletion prudentia/__init__.py
@@ -1,2 +1,2 @@
__version__ = '0.14'
__version__ = '0.15'
__author__ = 'Tiziano Perrucci'
2 changes: 2 additions & 0 deletions prudentia/cli.py
Expand Up @@ -10,6 +10,8 @@
cwd = path.dirname(path.realpath(__file__))
os.environ['ANSIBLE_CONFIG'] = path.join(cwd, 'ansible.cfg')
os.environ['ANSIBLE_ROLES_PATH'] = path.join(cwd, 'roles') + os.pathsep + '/etc/ansible/roles'
os.environ['ANSIBLE_LOOKUP_PLUGINS'] = path.join(cwd, 'plugins', 'lookup') + os.pathsep + '/usr/share/ansible_plugins/lookup_plugins'
os.environ['ANSIBLE_LIBRARY'] = path.join(cwd, 'modules')

from digital_ocean import DigitalOceanCli
from local import LocalCli
Expand Down
127 changes: 127 additions & 0 deletions prudentia/inventories/aws_elb_instances.py
@@ -0,0 +1,127 @@
#!/usr/bin/env python

####################################################################################
###
### Get EC2 instances inventory under ELB
### =====================================
###
### Generates inventory that Ansible can understand by making API request to
### AWS EC2 using the Boto library.
###
####################################################################################

import sys
import os
from boto import boto
from optparse import OptionParser
try:
import json
except:
import simplejson as json


AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID', '')
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY', '')
ELB_NAME = os.getenv('ELB_NAME', '')
HOSTS_NAME = os.getenv('HOSTS_NAME', '')


# Log an error to stderr and quit
def error(err_msg, err_operation=None):
if err_operation:
err_msg = 'Error {err_operation}: "{err_msg}"\n'.format(err_msg=err_msg, err_operation=err_operation)
else:
err_msg = 'Error: {err_msg}\n'.format(err_msg=err_msg)
sys.stderr.write(err_msg)
sys.exit(1)

# Get instance info
def get_instance_info(instances):
# Init ELB instance list
info = []
# Walk through the instance list
for instance in instances:
# Get instance info
try:
ec2_instance = ec2_conn.get_only_instances(instance.id)
for i in ec2_instance:
# Append instance info to the list
info.append(i.ip_address)
# Walk through instance info
except boto.exception.BotoServerError as e:
error("%s (%s)" % (e.message, e.error_code) , "fetching ELB instance properties")
# Return info
return info

# Get full instance list under each ELB
def get_elb_list():
# Init function return dictionary
elb_result = {}
# Walk through the ELB list
try:
for elb in elb_conn.get_all_load_balancers():
# Add list as a value to ELB name
elb_result[elb.name] = get_instance_info(elb.instances)
except boto.exception.BotoServerError as e:
error("%s (%s)" % (e.message, e.error_code) , "fetching ELB list")
# Return here
return elb_result

# Get full instance list under particular ELB
def get_elb_info(elb_name):
# Init function return dictionary
elb_result = []
# Get ELB info
try:
elb = elb_conn.get_all_load_balancers(elb_name)
for i in elb:
# Add list as a value to ELB name
elb_result = get_instance_info(i.instances)
except boto.exception.BotoServerError as e:
error("%s (%s)" % (e.message, e.error_code) , "fetching instances under ELB")

return elb_result

### Start the ball
# Parse the options
parser = OptionParser(usage="%prog [options] --list | --host <AWS ELB>")
parser.add_option('--list', default=False, dest="list", action="store_true", help="Produce a JSON consumable grouping of instances under ELB")
parser.add_option('--host', default=None, dest="elb", help="Generate additional host specific details for given host for Ansible")
(options, args) = parser.parse_args()

# Check if we have options and print help
if not options.list and not options.elb:
parser.print_help()
sys.exit(0)


# Try to connect to AWS
try:
elb_conn = boto.connect_elb()
except boto.exception.BotoServerError as e:
error("%s (%s)" % (e.message, e.error_code) , "connecting to ELB")

try:
ec2_conn = boto.connect_ec2()
except boto.exception.BotoServerError as e:
error("%s (%s)" % (e.message, e.error_code) , "connecting to EC2")

# Get instance details under all ELB
if ELB_NAME == '':
if options.list:
elb_list = get_elb_list()
print json.dumps(elb_list)
sys.exit(0)

# Get instance details under particular ELB
elif options.elb:
elb_info = get_elb_info(options.elb)
print json.dumps(elb_info)
sys.exit(0)
else:
elb_info = get_elb_info(ELB_NAME)
elb_hosts = elb_info
host_group = {HOSTS_NAME: {}}
host_group[HOSTS_NAME]['hosts'] = elb_hosts
print json.dumps(host_group)
sys.exit(0)
68 changes: 68 additions & 0 deletions prudentia/modules/hashi_vault_file.py
@@ -0,0 +1,68 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# [..] various imports

# this line must be written exactly that way,
# as Ansible will replace it with the "imported" code
from ansible.module_utils.basic import *

ANSIBLE_HASHI_VAULT_ADDR = 'http://127.0.0.1:8200'

if os.getenv('VAULT_ADDR') is not None:
ANSIBLE_HASHI_VAULT_ADDR = os.environ['VAULT_ADDR']


class HashiVaultFile:
def __init__(self, **kwargs):
try:
import hvac
except ImportError:
raise Exception("Please pip install hvac to use this module")

self.url = kwargs.pop('url')
self.secret = kwargs.pop('secret')
self.token = kwargs.pop('token')

self.client = hvac.Client(url=self.url, token=self.token)

if self.client.is_authenticated():
pass
else:
raise Exception("Invalid Hashicorp Vault Token Specified")

def get(self):
data = self.client.read(self.secret)
if data is None:
raise Exception("The secret %s doesn't seem to exist" % self.secret)
else:
return data['data']['value']


if __name__ == '__main__':
global module
module = AnsibleModule(
argument_spec={
'secret': {'required': True, 'type': 'str'},
'dest': {'required': True, 'type': 'str'},
'token': {'required': False, 'type': 'str'},
},
supports_check_mode=False
)

args = module.params

args['url'] = ANSIBLE_HASHI_VAULT_ADDR
try:
vault_conn = HashiVaultFile(**args)
value = vault_conn.get()

dest_file = os.path.abspath(args['dest'])

text_file = open(dest_file, "w")
text_file.write(value)
text_file.close()

module.exit_json(changed=True, file=dest_file)
except Exception, e:
module.fail_json(msg=str(e))
90 changes: 90 additions & 0 deletions prudentia/plugins/lookup/hashi_vault.py
@@ -0,0 +1,90 @@
# (c) 2015, Jonathan Davila <jdavila(at)ansible.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
# USAGE: {{ lookup('hashi_vault', 'secret=secret/hello token=c975b780-d1be-8016-866b-01d0f9b688a5 url=http://myvault:8200')}}
#
# You can skip setting the url if you set the VAULT_ADDR environment variable
# or if you want it to default to localhost:8200
#
# NOTE: Due to a current limitation in the HVAC library there won't
# necessarily be an error if a bad endpoint is specified.
#
# Requires hvac library. Install with pip.
#

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os

from ansible.errors import *

ANSIBLE_HASHI_VAULT_ADDR = 'http://127.0.0.1:8200'

if os.getenv('VAULT_ADDR') is not None:
ANSIBLE_HASHI_VAULT_ADDR = os.environ['VAULT_ADDR']


class HashiVaultLookup:
def __init__(self, **kwargs):
try:
import hvac
except ImportError:
AnsibleError("Please pip install hvac to use this module")

self.url = kwargs.pop('url')
self.secret = kwargs.pop('secret')
self.token = kwargs.pop('token')

self.client = hvac.Client(url=self.url, token=self.token)

if self.client.is_authenticated():
pass
else:
raise AnsibleError("Invalid Hashicorp Vault Token Specified")

def get(self):
data = self.client.read(self.secret)
if data is None:
raise AnsibleError("The secret %s doesn't seem to exist" % self.secret)
else:
return data['data']['value']


class LookupModule(object):
def __init__(self, basedir=None, **kwargs):
pass

def run(self, terms, inject=None, **kwargs):
vault_args = terms.split(' ')
vault_dict = {}
ret = []

for param in vault_args:
key, value = param.split('|')
vault_dict[key] = value

vault_conn = HashiVaultLookup(**vault_dict)
value = vault_conn.get()
ret.append(value)

if 'write_to_file' in vault_dict.keys():
text_file = open(vault_dict['write_to_file'], "w")
text_file.write(value)
text_file.close()

return ret
4 changes: 1 addition & 3 deletions prudentia/simple.py
Expand Up @@ -193,9 +193,7 @@ def __init__(self, name, general_type=None, box_extra_type=None):
self.vault_password = False
self.provisioned = False
self.tags = {}
pd = prudentia_python_dir()
self.extra_vars = {'prudentia_dir': pd}
self.load_vars(os.path.join(pd, 'vars', 'global.yml'), False)
self.extra_vars = {'prudentia_dir': prudentia_python_dir()}
self.load_tags()

def boxes(self):
Expand Down
27 changes: 27 additions & 0 deletions prudentia/tasks/mongodb_3.yml
@@ -0,0 +1,27 @@
---
# Parameters:
# prudentia_dir (provided)

- name: MongoDB | Check if is present
command: test -x /usr/bin/mongo
when: ansible_system == "Linux"
ignore_errors: yes
register: mongo_present
tags: mongodb3

- name: MongoDB | Add GPG key to apt keyring
apt_key: id=7F0CEB10 url=http://docs.mongodb.org/10gen-gpg-key.asc
sudo: yes
tags: mongodb3

- name: MongoDB | Add Debian apt repository
apt_repository: repo="deb http://repo.mongodb.org/apt/ubuntu {{ ansible_distribution_release }}/mongodb-org/3.0 multiverse"
when: ansible_os_family == "Debian" and mongo_present|failed
tags: mongodb3
sudo: yes

- name: MongoDB | Install
apt: update-cache=yes force=yes state=present pkg=mongodb-org
when: ansible_os_family == "Debian" and mongo_present|failed
sudo: yes
tags: mongodb3

0 comments on commit 068c593

Please sign in to comment.