diff --git a/.gitignore b/.gitignore index 26b8f268..1736d8cb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ settings/keys/* *.dot reports ENV +venv .DS_Store build deploy/last-update diff --git a/README.md b/README.md index 5eaf79d2..66fc4a29 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,32 @@ The partitioning between these modules is not as clean as would be ideal. `payme regluit was originally developed on Django 1.3 (python 2.7) and currently runs on Django 1.8. -Develop +Development (Vagrant + Virtualbox) +------- + +The recommended method for local development is to create a virtual machine with [Vagrant](https://www.vagrantup.com/) and [Virtualbox](https://www.virtualbox.org/wiki/Downloads). +With this method, the only requirements on the host machine are `virtualbox` and `vagrant`. +Vagrant will use the `ansible-local` provisioner, therefore installing python and ansible on the host machine is not necessary. + +__Instructions for Ubuntu 16:__ +1. Install virtualbox: `sudo apt-get install virtualbox` +2. Install vagrant: `sudo apt-get install vagrant` +3. Clone the `EbookFoundation/regluit` repository. +4. Navigate to the base directory of the cloned repo (where `Vagrantfile` is located). +5. Run `vagrant up` to create the VM, install dependencies, and start necessary services. + * Note: This step may take up to 15 minutes to complete. +6. Once the VM has been created, run `vagrant ssh` to log in to the virtual machine you just created. If provisioning was successful, you should see a success message upon login. + * If virtualenv doesn't activate upon login, you can do it manually by running `cd /opt/regluit && source venv/bin/activate` +7. Within the VM, run `./manage.py runserver 0.0.0.0:8000` to start the Django development server. +8. On your host machine, open your web browser of choice and navigate to `http://127.0.0.1:8000` + +__Instructions for other platforms (Windows/OSX):__ +* Steps are essentially the same, except for the installation of Vagrant and Virtualbox. Refer to each package's documentation for specific installation instructions. + +_NOTE:_ If running Windows on your host machine, ensure you are running `vagrant up` from an elevated command prompt, e.g. right click on Command Prompt -> Run As Administrator. + + +Development (Host Machine) ------- Here are some instructions for setting up regluit for development on diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 00000000..0ad9cdbc --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,56 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure("2") do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + # Every Vagrant development environment requires a box. You can search for + # boxes at https://vagrantcloud.com/search. + config.vm.box = "ubuntu/xenial64" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + config.vm.box_check_update = false + + # Setup specific for local machine + config.vm.define "regluit-local", primary: true do |local| + # Create a private network + local.vm.network "private_network", type: "dhcp" + local.vm.hostname = "regluit-local" + + # VirtuaLBox provider settings for running locally with Oracle VirtualBox + # --uartmode1 disconnected is necessary to disable serial interface, which + # is known to cause issues with Ubuntu 16 VM's + local.vm.provider "virtualbox" do |vb| + vb.name = "regluit-local" + vb.memory = 1024 + vb.cpus = 2 + vb.customize [ "modifyvm", :id, "--uartmode1", "disconnected" ] + end + + end + + config.vm.synced_folder ".", "/vagrant", disabled: true + config.vm.synced_folder ".", "/opt/regluit" + + config.vm.network "forwarded_port", guest: 8000, host: 8000 + + # Provision node with Ansible running on the Vagrant host + # This requires you have Ansible installed locally + # Vagrant autogenerates an ansible inventory file to use + config.vm.provision "ansible_local" do |ansible| + ansible.playbook = "/opt/regluit/provisioning/setup-regluit.yml" + ansible.provisioning_path = "/opt/regluit" + ansible.verbose = true + ansible.install = true + end + + config.vm.post_up_message = "Successfully created regluit-local VM. Run 'vagrant ssh' to log in and start the development server." + +end diff --git a/core/models/__init__.py b/core/models/__init__.py index 37917b8b..7f0ddf40 100755 --- a/core/models/__init__.py +++ b/core/models/__init__.py @@ -45,7 +45,7 @@ from regluit.payment.parameters import ( TRANSACTION_STATUS_FAILED, TRANSACTION_STATUS_INCOMPLETE ) -from regluit.utils import crypto +from regluit.utils import encryption as crypto from regluit.utils.localdatetime import now, date_today from regluit.core.parameters import ( diff --git a/provisioning/ec2.ini b/provisioning/ec2.ini new file mode 100644 index 00000000..c5ec6720 --- /dev/null +++ b/provisioning/ec2.ini @@ -0,0 +1,219 @@ +# Ansible EC2 external inventory script settings +# + +[ec2] + +# to talk to a private eucalyptus instance uncomment these lines +# and edit edit eucalyptus_host to be the host name of your cloud controller +#eucalyptus = True +#eucalyptus_host = clc.cloud.domain.org + +# AWS regions to make calls to. Set this to 'all' to make request to all regions +# in AWS and merge the results together. Alternatively, set this to a comma +# separated list of regions. E.g. 'us-east-1,us-west-1,us-west-2' and do not +# provide the 'regions_exclude' option. If this is set to 'auto', AWS_REGION or +# AWS_DEFAULT_REGION environment variable will be read to determine the region. +regions = all +regions_exclude = us-gov-west-1, cn-north-1 + +# When generating inventory, Ansible needs to know how to address a server. +# Each EC2 instance has a lot of variables associated with it. Here is the list: +# http://docs.pythonboto.org/en/latest/ref/ec2.html#module-boto.ec2.instance +# Below are 2 variables that are used as the address of a server: +# - destination_variable +# - vpc_destination_variable + +# This is the normal destination variable to use. If you are running Ansible +# from outside EC2, then 'public_dns_name' makes the most sense. If you are +# running Ansible from within EC2, then perhaps you want to use the internal +# address, and should set this to 'private_dns_name'. The key of an EC2 tag +# may optionally be used; however the boto instance variables hold precedence +# in the event of a collision. +destination_variable = public_dns_name + +# This allows you to override the inventory_name with an ec2 variable, instead +# of using the destination_variable above. Addressing (aka ansible_ssh_host) +# will still use destination_variable. Tags should be written as 'tag_TAGNAME'. +#hostname_variable = tag_Name + +# For server inside a VPC, using DNS names may not make sense. When an instance +# has 'subnet_id' set, this variable is used. If the subnet is public, setting +# this to 'ip_address' will return the public IP address. For instances in a +# private subnet, this should be set to 'private_ip_address', and Ansible must +# be run from within EC2. The key of an EC2 tag may optionally be used; however +# the boto instance variables hold precedence in the event of a collision. +# WARNING: - instances that are in the private vpc, _without_ public ip address +# will not be listed in the inventory until You set: +# vpc_destination_variable = private_ip_address +vpc_destination_variable = ip_address + +# The following two settings allow flexible ansible host naming based on a +# python format string and a comma-separated list of ec2 tags. Note that: +# +# 1) If the tags referenced are not present for some instances, empty strings +# will be substituted in the format string. +# 2) This overrides both destination_variable and vpc_destination_variable. +# +#destination_format = {0}.{1}.example.com +#destination_format_tags = Name,environment + +# To tag instances on EC2 with the resource records that point to them from +# Route53, set 'route53' to True. +route53 = False + +# To use Route53 records as the inventory hostnames, uncomment and set +# to equal the domain name you wish to use. You must also have 'route53' (above) +# set to True. +# route53_hostnames = .example.com + +# To exclude RDS instances from the inventory, uncomment and set to False. +#rds = False + +# To exclude ElastiCache instances from the inventory, uncomment and set to False. +#elasticache = False + +# Additionally, you can specify the list of zones to exclude looking up in +# 'route53_excluded_zones' as a comma-separated list. +# route53_excluded_zones = samplezone1.com, samplezone2.com + +# By default, only EC2 instances in the 'running' state are returned. Set +# 'all_instances' to True to return all instances regardless of state. +all_instances = False + +# By default, only EC2 instances in the 'running' state are returned. Specify +# EC2 instance states to return as a comma-separated list. This +# option is overridden when 'all_instances' is True. +# instance_states = pending, running, shutting-down, terminated, stopping, stopped + +# By default, only RDS instances in the 'available' state are returned. Set +# 'all_rds_instances' to True return all RDS instances regardless of state. +all_rds_instances = False + +# Include RDS cluster information (Aurora etc.) +include_rds_clusters = False + +# By default, only ElastiCache clusters and nodes in the 'available' state +# are returned. Set 'all_elasticache_clusters' and/or 'all_elastic_nodes' +# to True return all ElastiCache clusters and nodes, regardless of state. +# +# Note that all_elasticache_nodes only applies to listed clusters. That means +# if you set all_elastic_clusters to false, no node will be return from +# unavailable clusters, regardless of the state and to what you set for +# all_elasticache_nodes. +all_elasticache_replication_groups = False +all_elasticache_clusters = False +all_elasticache_nodes = False + +# API calls to EC2 are slow. For this reason, we cache the results of an API +# call. Set this to the path you want cache files to be written to. Two files +# will be written to this directory: +# - ansible-ec2.cache +# - ansible-ec2.index +cache_path = ~/.ansible/tmp + +# The number of seconds a cache file is considered valid. After this many +# seconds, a new API call will be made, and the cache file will be updated. +# To disable the cache, set this value to 0 +cache_max_age = 300 + +# Organize groups into a nested/hierarchy instead of a flat namespace. +nested_groups = False + +# Replace - tags when creating groups to avoid issues with ansible +replace_dash_in_groups = True + +# If set to true, any tag of the form "a,b,c" is expanded into a list +# and the results are used to create additional tag_* inventory groups. +expand_csv_tags = False + +# The EC2 inventory output can become very large. To manage its size, +# configure which groups should be created. +group_by_instance_id = True +group_by_region = True +group_by_availability_zone = True +group_by_aws_account = False +group_by_ami_id = True +group_by_instance_type = True +group_by_instance_state = False +group_by_platform = True +group_by_key_pair = True +group_by_vpc_id = True +group_by_security_group = True +group_by_tag_keys = True +group_by_tag_none = True +group_by_route53_names = True +group_by_rds_engine = True +group_by_rds_parameter_group = True +group_by_elasticache_engine = True +group_by_elasticache_cluster = True +group_by_elasticache_parameter_group = True +group_by_elasticache_replication_group = True + +# If you only want to include hosts that match a certain regular expression +# pattern_include = staging-* + +# If you want to exclude any hosts that match a certain regular expression +# pattern_exclude = staging-* + +# Instance filters can be used to control which instances are retrieved for +# inventory. For the full list of possible filters, please read the EC2 API +# docs: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html#query-DescribeInstances-filters +# Filters are key/value pairs separated by '=', to list multiple filters use +# a list separated by commas. To "AND" criteria together, use "&". Note that +# the "AND" is not useful along with stack_filters and so such usage is not allowed. +# See examples below. + +# If you want to apply multiple filters simultaneously, set stack_filters to +# True. Default behaviour is to combine the results of all filters. Stacking +# allows the use of multiple conditions to filter down, for example by +# environment and type of host. +stack_filters = False + +# Retrieve only instances with (key=value) env=staging tag +# instance_filters = tag:env=staging + +# Retrieve only instances with role=webservers OR role=dbservers tag +# instance_filters = tag:role=webservers,tag:role=dbservers + +# Retrieve only t1.micro instances OR instances with tag env=staging +# instance_filters = instance-type=t1.micro,tag:env=staging + +# You can use wildcards in filter values also. Below will list instances which +# tag Name value matches webservers1* +# (ex. webservers15, webservers1a, webservers123 etc) +# instance_filters = tag:Name=webservers1* + +# Retrieve only instances of type t1.micro that also have tag env=stage +# instance_filters = instance-type=t1.micro&tag:env=stage + +# Retrieve instances of type t1.micro AND tag env=stage, as well as any instance +# that are of type m3.large, regardless of env tag +# instance_filters = instance-type=t1.micro&tag:env=stage,instance-type=m3.large + +# An IAM role can be assumed, so all requests are run as that role. +# This can be useful for connecting across different accounts, or to limit user +# access +# iam_role = role-arn + +# A boto configuration profile may be used to separate out credentials +# see http://boto.readthedocs.org/en/latest/boto_config_tut.html +# boto_profile = some-boto-profile-name + + +[credentials] + +# The AWS credentials can optionally be specified here. Credentials specified +# here are ignored if the environment variable AWS_ACCESS_KEY_ID or +# AWS_PROFILE is set, or if the boto_profile property above is set. +# +# Supplying AWS credentials here is not recommended, as it introduces +# non-trivial security concerns. When going down this route, please make sure +# to set access permissions for this file correctly, e.g. handle it the same +# way as you would a private SSH key. +# +# Unlike the boto and AWS configure files, this section does not support +# profiles. +# +# aws_access_key_id = AXXXXXXXXXXXXXX +# aws_secret_access_key = XXXXXXXXXXXXXXXXXXX +# aws_security_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXX \ No newline at end of file diff --git a/provisioning/ec2.py b/provisioning/ec2.py new file mode 100644 index 00000000..a3db570f --- /dev/null +++ b/provisioning/ec2.py @@ -0,0 +1,1708 @@ +#!/usr/bin/env python + +''' +EC2 external inventory script +================================= + +Generates inventory that Ansible can understand by making API request to +AWS EC2 using the Boto library. + +NOTE: This script assumes Ansible is being executed where the environment +variables needed for Boto have already been set: + export AWS_ACCESS_KEY_ID='AK123' + export AWS_SECRET_ACCESS_KEY='abc123' + +Optional region environment variable if region is 'auto' + +This script also assumes that there is an ec2.ini file alongside it. To specify a +different path to ec2.ini, define the EC2_INI_PATH environment variable: + + export EC2_INI_PATH=/path/to/my_ec2.ini + +If you're using eucalyptus you need to set the above variables and +you need to define: + + export EC2_URL=http://hostname_of_your_cc:port/services/Eucalyptus + +If you're using boto profiles (requires boto>=2.24.0) you can choose a profile +using the --boto-profile command line argument (e.g. ec2.py --boto-profile prod) or using +the AWS_PROFILE variable: + + AWS_PROFILE=prod ansible-playbook -i ec2.py myplaybook.yml + +For more details, see: http://docs.pythonboto.org/en/latest/boto_config_tut.html + +You can filter for specific EC2 instances by creating an environment variable +named EC2_INSTANCE_FILTERS, which has the same format as the instance_filters +entry documented in ec2.ini. For example, to find all hosts whose name begins +with 'webserver', one might use: + + export EC2_INSTANCE_FILTERS='tag:Name=webserver*' + +When run against a specific host, this script returns the following variables: + - ec2_ami_launch_index + - ec2_architecture + - ec2_association + - ec2_attachTime + - ec2_attachment + - ec2_attachmentId + - ec2_block_devices + - ec2_client_token + - ec2_deleteOnTermination + - ec2_description + - ec2_deviceIndex + - ec2_dns_name + - ec2_eventsSet + - ec2_group_name + - ec2_hypervisor + - ec2_id + - ec2_image_id + - ec2_instanceState + - ec2_instance_type + - ec2_ipOwnerId + - ec2_ip_address + - ec2_item + - ec2_kernel + - ec2_key_name + - ec2_launch_time + - ec2_monitored + - ec2_monitoring + - ec2_networkInterfaceId + - ec2_ownerId + - ec2_persistent + - ec2_placement + - ec2_platform + - ec2_previous_state + - ec2_private_dns_name + - ec2_private_ip_address + - ec2_publicIp + - ec2_public_dns_name + - ec2_ramdisk + - ec2_reason + - ec2_region + - ec2_requester_id + - ec2_root_device_name + - ec2_root_device_type + - ec2_security_group_ids + - ec2_security_group_names + - ec2_shutdown_state + - ec2_sourceDestCheck + - ec2_spot_instance_request_id + - ec2_state + - ec2_state_code + - ec2_state_reason + - ec2_status + - ec2_subnet_id + - ec2_tenancy + - ec2_virtualization_type + - ec2_vpc_id + +These variables are pulled out of a boto.ec2.instance object. There is a lack of +consistency with variable spellings (camelCase and underscores) since this +just loops through all variables the object exposes. It is preferred to use the +ones with underscores when multiple exist. + +In addition, if an instance has AWS tags associated with it, each tag is a new +variable named: + - ec2_tag_[Key] = [Value] + +Security groups are comma-separated in 'ec2_security_group_ids' and +'ec2_security_group_names'. + +When destination_format and destination_format_tags are specified +the destination_format can be built from the instance tags and attributes. +The behavior will first check the user defined tags, then proceed to +check instance attributes, and finally if neither are found 'nil' will +be used instead. + +'my_instance': { + 'region': 'us-east-1', # attribute + 'availability_zone': 'us-east-1a', # attribute + 'private_dns_name': '172.31.0.1', # attribute + 'ec2_tag_deployment': 'blue', # tag + 'ec2_tag_clusterid': 'ansible', # tag + 'ec2_tag_Name': 'webserver', # tag + ... +} + +Inside of the ec2.ini file the following settings are specified: +... +destination_format: {0}-{1}-{2}-{3} +destination_format_tags: Name,clusterid,deployment,private_dns_name +... + +These settings would produce a destination_format as the following: +'webserver-ansible-blue-172.31.0.1' +''' + +# (c) 2012, Peter Sankauskas +# +# 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 . + +###################################################################### + +import sys +import os +import argparse +import re +from time import time +import boto +from boto import ec2 +from boto import rds +from boto import elasticache +from boto import route53 +from boto import sts +import six + +from ansible.module_utils import ec2 as ec2_utils + +HAS_BOTO3 = False +try: + import boto3 # noqa + HAS_BOTO3 = True +except ImportError: + pass + +from six.moves import configparser +from collections import defaultdict + +try: + import json +except ImportError: + import simplejson as json + +DEFAULTS = { + 'all_elasticache_clusters': 'False', + 'all_elasticache_nodes': 'False', + 'all_elasticache_replication_groups': 'False', + 'all_instances': 'False', + 'all_rds_instances': 'False', + 'aws_access_key_id': None, + 'aws_secret_access_key': None, + 'aws_security_token': None, + 'boto_profile': None, + 'cache_max_age': '300', + 'cache_path': '~/.ansible/tmp', + 'destination_variable': 'public_dns_name', + 'elasticache': 'True', + 'eucalyptus': 'False', + 'eucalyptus_host': None, + 'expand_csv_tags': 'False', + 'group_by_ami_id': 'True', + 'group_by_availability_zone': 'True', + 'group_by_aws_account': 'False', + 'group_by_elasticache_cluster': 'True', + 'group_by_elasticache_engine': 'True', + 'group_by_elasticache_parameter_group': 'True', + 'group_by_elasticache_replication_group': 'True', + 'group_by_instance_id': 'True', + 'group_by_instance_state': 'False', + 'group_by_instance_type': 'True', + 'group_by_key_pair': 'True', + 'group_by_platform': 'True', + 'group_by_rds_engine': 'True', + 'group_by_rds_parameter_group': 'True', + 'group_by_region': 'True', + 'group_by_route53_names': 'True', + 'group_by_security_group': 'True', + 'group_by_tag_keys': 'True', + 'group_by_tag_none': 'True', + 'group_by_vpc_id': 'True', + 'hostname_variable': None, + 'iam_role': None, + 'include_rds_clusters': 'False', + 'nested_groups': 'False', + 'pattern_exclude': None, + 'pattern_include': None, + 'rds': 'False', + 'regions': 'all', + 'regions_exclude': 'us-gov-west-1, cn-north-1', + 'replace_dash_in_groups': 'True', + 'route53': 'False', + 'route53_excluded_zones': '', + 'route53_hostnames': None, + 'stack_filters': 'False', + 'vpc_destination_variable': 'ip_address' +} + + +class Ec2Inventory(object): + + def _empty_inventory(self): + return {"_meta": {"hostvars": {}}} + + def __init__(self): + ''' Main execution path ''' + + # Inventory grouped by instance IDs, tags, security groups, regions, + # and availability zones + self.inventory = self._empty_inventory() + + self.aws_account_id = None + + # Index of hostname (address) to instance ID + self.index = {} + + # Boto profile to use (if any) + self.boto_profile = None + + # AWS credentials. + self.credentials = {} + + # Read settings and parse CLI arguments + self.parse_cli_args() + self.read_settings() + + # Make sure that profile_name is not passed at all if not set + # as pre 2.24 boto will fall over otherwise + if self.boto_profile: + if not hasattr(boto.ec2.EC2Connection, 'profile_name'): + self.fail_with_error("boto version must be >= 2.24 to use profile") + + # Cache + if self.args.refresh_cache: + self.do_api_calls_update_cache() + elif not self.is_cache_valid(): + self.do_api_calls_update_cache() + + # Data to print + if self.args.host: + data_to_print = self.get_host_info() + + elif self.args.list: + # Display list of instances for inventory + if self.inventory == self._empty_inventory(): + data_to_print = self.get_inventory_from_cache() + else: + data_to_print = self.json_format_dict(self.inventory, True) + + print(data_to_print) + + def is_cache_valid(self): + ''' Determines if the cache files have expired, or if it is still valid ''' + + if os.path.isfile(self.cache_path_cache): + mod_time = os.path.getmtime(self.cache_path_cache) + current_time = time() + if (mod_time + self.cache_max_age) > current_time: + if os.path.isfile(self.cache_path_index): + return True + + return False + + def read_settings(self): + ''' Reads the settings from the ec2.ini file ''' + + scriptbasename = __file__ + scriptbasename = os.path.basename(scriptbasename) + scriptbasename = scriptbasename.replace('.py', '') + + defaults = { + 'ec2': { + 'ini_fallback': os.path.join(os.path.dirname(__file__), 'ec2.ini'), + 'ini_path': os.path.join(os.path.dirname(__file__), '%s.ini' % scriptbasename) + } + } + + if six.PY3: + config = configparser.ConfigParser(DEFAULTS) + else: + config = configparser.SafeConfigParser(DEFAULTS) + ec2_ini_path = os.environ.get('EC2_INI_PATH', defaults['ec2']['ini_path']) + ec2_ini_path = os.path.expanduser(os.path.expandvars(ec2_ini_path)) + + if not os.path.isfile(ec2_ini_path): + ec2_ini_path = os.path.expanduser(defaults['ec2']['ini_fallback']) + + if os.path.isfile(ec2_ini_path): + config.read(ec2_ini_path) + + # Add empty sections if they don't exist + try: + config.add_section('ec2') + except configparser.DuplicateSectionError: + pass + + try: + config.add_section('credentials') + except configparser.DuplicateSectionError: + pass + + # is eucalyptus? + self.eucalyptus = config.getboolean('ec2', 'eucalyptus') + self.eucalyptus_host = config.get('ec2', 'eucalyptus_host') + + # Regions + self.regions = [] + config_regions = config.get('ec2', 'regions') + if (config_regions == 'all'): + if self.eucalyptus_host: + self.regions.append(boto.connect_euca(host=self.eucalyptus_host).region.name, **self.credentials) + else: + config_regions_exclude = config.get('ec2', 'regions_exclude') + + for region_info in ec2.regions(): + if region_info.name not in config_regions_exclude: + self.regions.append(region_info.name) + else: + self.regions = config_regions.split(",") + if 'auto' in self.regions: + env_region = os.environ.get('AWS_REGION') + if env_region is None: + env_region = os.environ.get('AWS_DEFAULT_REGION') + self.regions = [env_region] + + # Destination addresses + self.destination_variable = config.get('ec2', 'destination_variable') + self.vpc_destination_variable = config.get('ec2', 'vpc_destination_variable') + self.hostname_variable = config.get('ec2', 'hostname_variable') + + if config.has_option('ec2', 'destination_format') and \ + config.has_option('ec2', 'destination_format_tags'): + self.destination_format = config.get('ec2', 'destination_format') + self.destination_format_tags = config.get('ec2', 'destination_format_tags').split(',') + else: + self.destination_format = None + self.destination_format_tags = None + + # Route53 + self.route53_enabled = config.getboolean('ec2', 'route53') + self.route53_hostnames = config.get('ec2', 'route53_hostnames') + + self.route53_excluded_zones = [] + self.route53_excluded_zones = [a for a in config.get('ec2', 'route53_excluded_zones').split(',') if a] + + # Include RDS instances? + self.rds_enabled = config.getboolean('ec2', 'rds') + + # Include RDS cluster instances? + self.include_rds_clusters = config.getboolean('ec2', 'include_rds_clusters') + + # Include ElastiCache instances? + self.elasticache_enabled = config.getboolean('ec2', 'elasticache') + + # Return all EC2 instances? + self.all_instances = config.getboolean('ec2', 'all_instances') + + # Instance states to be gathered in inventory. Default is 'running'. + # Setting 'all_instances' to 'yes' overrides this option. + ec2_valid_instance_states = [ + 'pending', + 'running', + 'shutting-down', + 'terminated', + 'stopping', + 'stopped' + ] + self.ec2_instance_states = [] + if self.all_instances: + self.ec2_instance_states = ec2_valid_instance_states + elif config.has_option('ec2', 'instance_states'): + for instance_state in config.get('ec2', 'instance_states').split(','): + instance_state = instance_state.strip() + if instance_state not in ec2_valid_instance_states: + continue + self.ec2_instance_states.append(instance_state) + else: + self.ec2_instance_states = ['running'] + + # Return all RDS instances? (if RDS is enabled) + self.all_rds_instances = config.getboolean('ec2', 'all_rds_instances') + + # Return all ElastiCache replication groups? (if ElastiCache is enabled) + self.all_elasticache_replication_groups = config.getboolean('ec2', 'all_elasticache_replication_groups') + + # Return all ElastiCache clusters? (if ElastiCache is enabled) + self.all_elasticache_clusters = config.getboolean('ec2', 'all_elasticache_clusters') + + # Return all ElastiCache nodes? (if ElastiCache is enabled) + self.all_elasticache_nodes = config.getboolean('ec2', 'all_elasticache_nodes') + + # boto configuration profile (prefer CLI argument then environment variables then config file) + self.boto_profile = self.args.boto_profile or \ + os.environ.get('AWS_PROFILE') or \ + config.get('ec2', 'boto_profile') + + # AWS credentials (prefer environment variables) + if not (self.boto_profile or os.environ.get('AWS_ACCESS_KEY_ID') or + os.environ.get('AWS_PROFILE')): + + aws_access_key_id = config.get('credentials', 'aws_access_key_id') + aws_secret_access_key = config.get('credentials', 'aws_secret_access_key') + aws_security_token = config.get('credentials', 'aws_security_token') + + if aws_access_key_id: + self.credentials = { + 'aws_access_key_id': aws_access_key_id, + 'aws_secret_access_key': aws_secret_access_key + } + if aws_security_token: + self.credentials['security_token'] = aws_security_token + + # Cache related + cache_dir = os.path.expanduser(config.get('ec2', 'cache_path')) + if self.boto_profile: + cache_dir = os.path.join(cache_dir, 'profile_' + self.boto_profile) + if not os.path.exists(cache_dir): + os.makedirs(cache_dir) + + cache_name = 'ansible-ec2' + cache_id = self.boto_profile or os.environ.get('AWS_ACCESS_KEY_ID', self.credentials.get('aws_access_key_id')) + if cache_id: + cache_name = '%s-%s' % (cache_name, cache_id) + cache_name += '-' + str(abs(hash(__file__)))[1:7] + self.cache_path_cache = os.path.join(cache_dir, "%s.cache" % cache_name) + self.cache_path_index = os.path.join(cache_dir, "%s.index" % cache_name) + self.cache_max_age = config.getint('ec2', 'cache_max_age') + + self.expand_csv_tags = config.getboolean('ec2', 'expand_csv_tags') + + # Configure nested groups instead of flat namespace. + self.nested_groups = config.getboolean('ec2', 'nested_groups') + + # Replace dash or not in group names + self.replace_dash_in_groups = config.getboolean('ec2', 'replace_dash_in_groups') + + # IAM role to assume for connection + self.iam_role = config.get('ec2', 'iam_role') + + # Configure which groups should be created. + + group_by_options = [a for a in DEFAULTS if a.startswith('group_by')] + for option in group_by_options: + setattr(self, option, config.getboolean('ec2', option)) + + # Do we need to just include hosts that match a pattern? + self.pattern_include = config.get('ec2', 'pattern_include') + if self.pattern_include: + self.pattern_include = re.compile(self.pattern_include) + + # Do we need to exclude hosts that match a pattern? + self.pattern_exclude = config.get('ec2', 'pattern_exclude') + if self.pattern_exclude: + self.pattern_exclude = re.compile(self.pattern_exclude) + + # Do we want to stack multiple filters? + self.stack_filters = config.getboolean('ec2', 'stack_filters') + + # Instance filters (see boto and EC2 API docs). Ignore invalid filters. + self.ec2_instance_filters = [] + + if config.has_option('ec2', 'instance_filters') or 'EC2_INSTANCE_FILTERS' in os.environ: + filters = os.getenv('EC2_INSTANCE_FILTERS', config.get('ec2', 'instance_filters') if config.has_option('ec2', 'instance_filters') else '') + + if self.stack_filters and '&' in filters: + self.fail_with_error("AND filters along with stack_filter enabled is not supported.\n") + + filter_sets = [f for f in filters.split(',') if f] + + for filter_set in filter_sets: + filters = {} + filter_set = filter_set.strip() + for instance_filter in filter_set.split("&"): + instance_filter = instance_filter.strip() + if not instance_filter or '=' not in instance_filter: + continue + filter_key, filter_value = [x.strip() for x in instance_filter.split('=', 1)] + if not filter_key: + continue + filters[filter_key] = filter_value + self.ec2_instance_filters.append(filters.copy()) + + def parse_cli_args(self): + ''' Command line argument processing ''' + + parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on EC2') + parser.add_argument('--list', action='store_true', default=True, + help='List instances (default: True)') + parser.add_argument('--host', action='store', + help='Get all the variables about a specific instance') + parser.add_argument('--refresh-cache', action='store_true', default=False, + help='Force refresh of cache by making API requests to EC2 (default: False - use cache files)') + parser.add_argument('--profile', '--boto-profile', action='store', dest='boto_profile', + help='Use boto profile for connections to EC2') + self.args = parser.parse_args() + + def do_api_calls_update_cache(self): + ''' Do API calls to each region, and save data in cache files ''' + + if self.route53_enabled: + self.get_route53_records() + + for region in self.regions: + self.get_instances_by_region(region) + if self.rds_enabled: + self.get_rds_instances_by_region(region) + if self.elasticache_enabled: + self.get_elasticache_clusters_by_region(region) + self.get_elasticache_replication_groups_by_region(region) + if self.include_rds_clusters: + self.include_rds_clusters_by_region(region) + + self.write_to_cache(self.inventory, self.cache_path_cache) + self.write_to_cache(self.index, self.cache_path_index) + + def connect(self, region): + ''' create connection to api server''' + if self.eucalyptus: + conn = boto.connect_euca(host=self.eucalyptus_host, **self.credentials) + conn.APIVersion = '2010-08-31' + else: + conn = self.connect_to_aws(ec2, region) + return conn + + def boto_fix_security_token_in_profile(self, connect_args): + ''' monkey patch for boto issue boto/boto#2100 ''' + profile = 'profile ' + self.boto_profile + if boto.config.has_option(profile, 'aws_security_token'): + connect_args['security_token'] = boto.config.get(profile, 'aws_security_token') + return connect_args + + def connect_to_aws(self, module, region): + connect_args = self.credentials + + # only pass the profile name if it's set (as it is not supported by older boto versions) + if self.boto_profile: + connect_args['profile_name'] = self.boto_profile + self.boto_fix_security_token_in_profile(connect_args) + + if self.iam_role: + sts_conn = sts.connect_to_region(region, **connect_args) + role = sts_conn.assume_role(self.iam_role, 'ansible_dynamic_inventory') + connect_args['aws_access_key_id'] = role.credentials.access_key + connect_args['aws_secret_access_key'] = role.credentials.secret_key + connect_args['security_token'] = role.credentials.session_token + + conn = module.connect_to_region(region, **connect_args) + # connect_to_region will fail "silently" by returning None if the region name is wrong or not supported + if conn is None: + self.fail_with_error("region name: %s likely not supported, or AWS is down. connection to region failed." % region) + return conn + + def get_instances_by_region(self, region): + ''' Makes an AWS EC2 API call to the list of instances in a particular + region ''' + + try: + conn = self.connect(region) + reservations = [] + if self.ec2_instance_filters: + if self.stack_filters: + filters_dict = {} + for filters in self.ec2_instance_filters: + filters_dict.update(filters) + reservations.extend(conn.get_all_instances(filters=filters_dict)) + else: + for filters in self.ec2_instance_filters: + reservations.extend(conn.get_all_instances(filters=filters)) + else: + reservations = conn.get_all_instances() + + # Pull the tags back in a second step + # AWS are on record as saying that the tags fetched in the first `get_all_instances` request are not + # reliable and may be missing, and the only way to guarantee they are there is by calling `get_all_tags` + instance_ids = [] + for reservation in reservations: + instance_ids.extend([instance.id for instance in reservation.instances]) + + max_filter_value = 199 + tags = [] + for i in range(0, len(instance_ids), max_filter_value): + tags.extend(conn.get_all_tags(filters={'resource-type': 'instance', 'resource-id': instance_ids[i:i + max_filter_value]})) + + tags_by_instance_id = defaultdict(dict) + for tag in tags: + tags_by_instance_id[tag.res_id][tag.name] = tag.value + + if (not self.aws_account_id) and reservations: + self.aws_account_id = reservations[0].owner_id + + for reservation in reservations: + for instance in reservation.instances: + instance.tags = tags_by_instance_id[instance.id] + self.add_instance(instance, region) + + except boto.exception.BotoServerError as e: + if e.error_code == 'AuthFailure': + error = self.get_auth_error_message() + else: + backend = 'Eucalyptus' if self.eucalyptus else 'AWS' + error = "Error connecting to %s backend.\n%s" % (backend, e.message) + self.fail_with_error(error, 'getting EC2 instances') + + def tags_match_filters(self, tags): + ''' return True if given tags match configured filters ''' + if not self.ec2_instance_filters: + return True + + for filters in self.ec2_instance_filters: + for filter_name, filter_value in filters.items(): + if filter_name[:4] != 'tag:': + continue + filter_name = filter_name[4:] + if filter_name not in tags: + if self.stack_filters: + return False + continue + if isinstance(filter_value, list): + if self.stack_filters and tags[filter_name] not in filter_value: + return False + if not self.stack_filters and tags[filter_name] in filter_value: + return True + if isinstance(filter_value, six.string_types): + if self.stack_filters and tags[filter_name] != filter_value: + return False + if not self.stack_filters and tags[filter_name] == filter_value: + return True + + return self.stack_filters + + def get_rds_instances_by_region(self, region): + ''' Makes an AWS API call to the list of RDS instances in a particular + region ''' + + if not HAS_BOTO3: + self.fail_with_error("Working with RDS instances requires boto3 - please install boto3 and try again", + "getting RDS instances") + + client = ec2_utils.boto3_inventory_conn('client', 'rds', region, **self.credentials) + db_instances = client.describe_db_instances() + + try: + conn = self.connect_to_aws(rds, region) + if conn: + marker = None + while True: + instances = conn.get_all_dbinstances(marker=marker) + marker = instances.marker + for index, instance in enumerate(instances): + # Add tags to instances. + instance.arn = db_instances['DBInstances'][index]['DBInstanceArn'] + tags = client.list_tags_for_resource(ResourceName=instance.arn)['TagList'] + instance.tags = {} + for tag in tags: + instance.tags[tag['Key']] = tag['Value'] + if self.tags_match_filters(instance.tags): + self.add_rds_instance(instance, region) + if not marker: + break + except boto.exception.BotoServerError as e: + error = e.reason + + if e.error_code == 'AuthFailure': + error = self.get_auth_error_message() + elif e.error_code == "OptInRequired": + error = "RDS hasn't been enabled for this account yet. " \ + "You must either log in to the RDS service through the AWS console to enable it, " \ + "or set 'rds = False' in ec2.ini" + elif not e.reason == "Forbidden": + error = "Looks like AWS RDS is down:\n%s" % e.message + self.fail_with_error(error, 'getting RDS instances') + + def include_rds_clusters_by_region(self, region): + if not HAS_BOTO3: + self.fail_with_error("Working with RDS clusters requires boto3 - please install boto3 and try again", + "getting RDS clusters") + + client = ec2_utils.boto3_inventory_conn('client', 'rds', region, **self.credentials) + + marker, clusters = '', [] + while marker is not None: + resp = client.describe_db_clusters(Marker=marker) + clusters.extend(resp["DBClusters"]) + marker = resp.get('Marker', None) + + account_id = boto.connect_iam().get_user().arn.split(':')[4] + c_dict = {} + for c in clusters: + # remove these datetime objects as there is no serialisation to json + # currently in place and we don't need the data yet + if 'EarliestRestorableTime' in c: + del c['EarliestRestorableTime'] + if 'LatestRestorableTime' in c: + del c['LatestRestorableTime'] + + if not self.ec2_instance_filters: + matches_filter = True + else: + matches_filter = False + + try: + # arn:aws:rds:::: + tags = client.list_tags_for_resource( + ResourceName='arn:aws:rds:' + region + ':' + account_id + ':cluster:' + c['DBClusterIdentifier']) + c['Tags'] = tags['TagList'] + + if self.ec2_instance_filters: + for filters in self.ec2_instance_filters: + for filter_key, filter_values in filters.items(): + # get AWS tag key e.g. tag:env will be 'env' + tag_name = filter_key.split(":", 1)[1] + # Filter values is a list (if you put multiple values for the same tag name) + matches_filter = any(d['Key'] == tag_name and d['Value'] in filter_values for d in c['Tags']) + + if matches_filter: + # it matches a filter, so stop looking for further matches + break + + if matches_filter: + break + + except Exception as e: + if e.message.find('DBInstanceNotFound') >= 0: + # AWS RDS bug (2016-01-06) means deletion does not fully complete and leave an 'empty' cluster. + # Ignore errors when trying to find tags for these + pass + + # ignore empty clusters caused by AWS bug + if len(c['DBClusterMembers']) == 0: + continue + elif matches_filter: + c_dict[c['DBClusterIdentifier']] = c + + self.inventory['db_clusters'] = c_dict + + def get_elasticache_clusters_by_region(self, region): + ''' Makes an AWS API call to the list of ElastiCache clusters (with + nodes' info) in a particular region.''' + + # ElastiCache boto module doesn't provide a get_all_instances method, + # that's why we need to call describe directly (it would be called by + # the shorthand method anyway...) + try: + conn = self.connect_to_aws(elasticache, region) + if conn: + # show_cache_node_info = True + # because we also want nodes' information + response = conn.describe_cache_clusters(None, None, None, True) + + except boto.exception.BotoServerError as e: + error = e.reason + + if e.error_code == 'AuthFailure': + error = self.get_auth_error_message() + elif e.error_code == "OptInRequired": + error = "ElastiCache hasn't been enabled for this account yet. " \ + "You must either log in to the ElastiCache service through the AWS console to enable it, " \ + "or set 'elasticache = False' in ec2.ini" + elif not e.reason == "Forbidden": + error = "Looks like AWS ElastiCache is down:\n%s" % e.message + self.fail_with_error(error, 'getting ElastiCache clusters') + + try: + # Boto also doesn't provide wrapper classes to CacheClusters or + # CacheNodes. Because of that we can't make use of the get_list + # method in the AWSQueryConnection. Let's do the work manually + clusters = response['DescribeCacheClustersResponse']['DescribeCacheClustersResult']['CacheClusters'] + + except KeyError as e: + error = "ElastiCache query to AWS failed (unexpected format)." + self.fail_with_error(error, 'getting ElastiCache clusters') + + for cluster in clusters: + self.add_elasticache_cluster(cluster, region) + + def get_elasticache_replication_groups_by_region(self, region): + ''' Makes an AWS API call to the list of ElastiCache replication groups + in a particular region.''' + + # ElastiCache boto module doesn't provide a get_all_instances method, + # that's why we need to call describe directly (it would be called by + # the shorthand method anyway...) + try: + conn = self.connect_to_aws(elasticache, region) + if conn: + response = conn.describe_replication_groups() + + except boto.exception.BotoServerError as e: + error = e.reason + + if e.error_code == 'AuthFailure': + error = self.get_auth_error_message() + if not e.reason == "Forbidden": + error = "Looks like AWS ElastiCache [Replication Groups] is down:\n%s" % e.message + self.fail_with_error(error, 'getting ElastiCache clusters') + + try: + # Boto also doesn't provide wrapper classes to ReplicationGroups + # Because of that we can't make use of the get_list method in the + # AWSQueryConnection. Let's do the work manually + replication_groups = response['DescribeReplicationGroupsResponse']['DescribeReplicationGroupsResult']['ReplicationGroups'] + + except KeyError as e: + error = "ElastiCache [Replication Groups] query to AWS failed (unexpected format)." + self.fail_with_error(error, 'getting ElastiCache clusters') + + for replication_group in replication_groups: + self.add_elasticache_replication_group(replication_group, region) + + def get_auth_error_message(self): + ''' create an informative error message if there is an issue authenticating''' + errors = ["Authentication error retrieving ec2 inventory."] + if None in [os.environ.get('AWS_ACCESS_KEY_ID'), os.environ.get('AWS_SECRET_ACCESS_KEY')]: + errors.append(' - No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY environment vars found') + else: + errors.append(' - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment vars found but may not be correct') + + boto_paths = ['/etc/boto.cfg', '~/.boto', '~/.aws/credentials'] + boto_config_found = [p for p in boto_paths if os.path.isfile(os.path.expanduser(p))] + if len(boto_config_found) > 0: + errors.append(" - Boto configs found at '%s', but the credentials contained may not be correct" % ', '.join(boto_config_found)) + else: + errors.append(" - No Boto config found at any expected location '%s'" % ', '.join(boto_paths)) + + return '\n'.join(errors) + + def fail_with_error(self, err_msg, err_operation=None): + '''log an error to std err for ansible-playbook to consume and exit''' + if err_operation: + err_msg = 'ERROR: "{err_msg}", while: {err_operation}'.format( + err_msg=err_msg, err_operation=err_operation) + sys.stderr.write(err_msg) + sys.exit(1) + + def get_instance(self, region, instance_id): + conn = self.connect(region) + + reservations = conn.get_all_instances([instance_id]) + for reservation in reservations: + for instance in reservation.instances: + return instance + + def add_instance(self, instance, region): + ''' Adds an instance to the inventory and index, as long as it is + addressable ''' + + # Only return instances with desired instance states + if instance.state not in self.ec2_instance_states: + return + + # Select the best destination address + # When destination_format and destination_format_tags are specified + # the following code will attempt to find the instance tags first, + # then the instance attributes next, and finally if neither are found + # assign nil for the desired destination format attribute. + if self.destination_format and self.destination_format_tags: + dest_vars = [] + inst_tags = getattr(instance, 'tags') + for tag in self.destination_format_tags: + if tag in inst_tags: + dest_vars.append(inst_tags[tag]) + elif hasattr(instance, tag): + dest_vars.append(getattr(instance, tag)) + else: + dest_vars.append('nil') + + dest = self.destination_format.format(*dest_vars) + elif instance.subnet_id: + dest = getattr(instance, self.vpc_destination_variable, None) + if dest is None: + dest = getattr(instance, 'tags').get(self.vpc_destination_variable, None) + else: + dest = getattr(instance, self.destination_variable, None) + if dest is None: + dest = getattr(instance, 'tags').get(self.destination_variable, None) + + if not dest: + # Skip instances we cannot address (e.g. private VPC subnet) + return + + # Set the inventory name + hostname = None + if self.hostname_variable: + if self.hostname_variable.startswith('tag_'): + hostname = instance.tags.get(self.hostname_variable[4:], None) + else: + hostname = getattr(instance, self.hostname_variable) + + # set the hostname from route53 + if self.route53_enabled and self.route53_hostnames: + route53_names = self.get_instance_route53_names(instance) + for name in route53_names: + if name.endswith(self.route53_hostnames): + hostname = name + + # If we can't get a nice hostname, use the destination address + if not hostname: + hostname = dest + # to_safe strips hostname characters like dots, so don't strip route53 hostnames + elif self.route53_enabled and self.route53_hostnames and hostname.endswith(self.route53_hostnames): + hostname = hostname.lower() + else: + hostname = self.to_safe(hostname).lower() + + # if we only want to include hosts that match a pattern, skip those that don't + if self.pattern_include and not self.pattern_include.match(hostname): + return + + # if we need to exclude hosts that match a pattern, skip those + if self.pattern_exclude and self.pattern_exclude.match(hostname): + return + + # Add to index + self.index[hostname] = [region, instance.id] + + # Inventory: Group by instance ID (always a group of 1) + if self.group_by_instance_id: + self.inventory[instance.id] = [hostname] + if self.nested_groups: + self.push_group(self.inventory, 'instances', instance.id) + + # Inventory: Group by region + if self.group_by_region: + self.push(self.inventory, region, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'regions', region) + + # Inventory: Group by availability zone + if self.group_by_availability_zone: + self.push(self.inventory, instance.placement, hostname) + if self.nested_groups: + if self.group_by_region: + self.push_group(self.inventory, region, instance.placement) + self.push_group(self.inventory, 'zones', instance.placement) + + # Inventory: Group by Amazon Machine Image (AMI) ID + if self.group_by_ami_id: + ami_id = self.to_safe(instance.image_id) + self.push(self.inventory, ami_id, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'images', ami_id) + + # Inventory: Group by instance type + if self.group_by_instance_type: + type_name = self.to_safe('type_' + instance.instance_type) + self.push(self.inventory, type_name, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'types', type_name) + + # Inventory: Group by instance state + if self.group_by_instance_state: + state_name = self.to_safe('instance_state_' + instance.state) + self.push(self.inventory, state_name, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'instance_states', state_name) + + # Inventory: Group by platform + if self.group_by_platform: + if instance.platform: + platform = self.to_safe('platform_' + instance.platform) + else: + platform = self.to_safe('platform_undefined') + self.push(self.inventory, platform, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'platforms', platform) + + # Inventory: Group by key pair + if self.group_by_key_pair and instance.key_name: + key_name = self.to_safe('key_' + instance.key_name) + self.push(self.inventory, key_name, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'keys', key_name) + + # Inventory: Group by VPC + if self.group_by_vpc_id and instance.vpc_id: + vpc_id_name = self.to_safe('vpc_id_' + instance.vpc_id) + self.push(self.inventory, vpc_id_name, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'vpcs', vpc_id_name) + + # Inventory: Group by security group + if self.group_by_security_group: + try: + for group in instance.groups: + key = self.to_safe("security_group_" + group.name) + self.push(self.inventory, key, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'security_groups', key) + except AttributeError: + self.fail_with_error('\n'.join(['Package boto seems a bit older.', + 'Please upgrade boto >= 2.3.0.'])) + + # Inventory: Group by AWS account ID + if self.group_by_aws_account: + self.push(self.inventory, self.aws_account_id, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'accounts', self.aws_account_id) + + # Inventory: Group by tag keys + if self.group_by_tag_keys: + for k, v in instance.tags.items(): + if self.expand_csv_tags and v and ',' in v: + values = map(lambda x: x.strip(), v.split(',')) + else: + values = [v] + + for v in values: + if v: + key = self.to_safe("tag_" + k + "=" + v) + else: + key = self.to_safe("tag_" + k) + self.push(self.inventory, key, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'tags', self.to_safe("tag_" + k)) + if v: + self.push_group(self.inventory, self.to_safe("tag_" + k), key) + + # Inventory: Group by Route53 domain names if enabled + if self.route53_enabled and self.group_by_route53_names: + route53_names = self.get_instance_route53_names(instance) + for name in route53_names: + self.push(self.inventory, name, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'route53', name) + + # Global Tag: instances without tags + if self.group_by_tag_none and len(instance.tags) == 0: + self.push(self.inventory, 'tag_none', hostname) + if self.nested_groups: + self.push_group(self.inventory, 'tags', 'tag_none') + + # Global Tag: tag all EC2 instances + self.push(self.inventory, 'ec2', hostname) + + self.inventory["_meta"]["hostvars"][hostname] = self.get_host_info_dict_from_instance(instance) + self.inventory["_meta"]["hostvars"][hostname]['ansible_host'] = dest + + def add_rds_instance(self, instance, region): + ''' Adds an RDS instance to the inventory and index, as long as it is + addressable ''' + + # Only want available instances unless all_rds_instances is True + if not self.all_rds_instances and instance.status != 'available': + return + + # Select the best destination address + dest = instance.endpoint[0] + + if not dest: + # Skip instances we cannot address (e.g. private VPC subnet) + return + + # Set the inventory name + hostname = None + if self.hostname_variable: + if self.hostname_variable.startswith('tag_'): + hostname = instance.tags.get(self.hostname_variable[4:], None) + else: + hostname = getattr(instance, self.hostname_variable) + + # If we can't get a nice hostname, use the destination address + if not hostname: + hostname = dest + + hostname = self.to_safe(hostname).lower() + + # Add to index + self.index[hostname] = [region, instance.id] + + # Inventory: Group by instance ID (always a group of 1) + if self.group_by_instance_id: + self.inventory[instance.id] = [hostname] + if self.nested_groups: + self.push_group(self.inventory, 'instances', instance.id) + + # Inventory: Group by region + if self.group_by_region: + self.push(self.inventory, region, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'regions', region) + + # Inventory: Group by availability zone + if self.group_by_availability_zone: + self.push(self.inventory, instance.availability_zone, hostname) + if self.nested_groups: + if self.group_by_region: + self.push_group(self.inventory, region, instance.availability_zone) + self.push_group(self.inventory, 'zones', instance.availability_zone) + + # Inventory: Group by instance type + if self.group_by_instance_type: + type_name = self.to_safe('type_' + instance.instance_class) + self.push(self.inventory, type_name, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'types', type_name) + + # Inventory: Group by VPC + if self.group_by_vpc_id and instance.subnet_group and instance.subnet_group.vpc_id: + vpc_id_name = self.to_safe('vpc_id_' + instance.subnet_group.vpc_id) + self.push(self.inventory, vpc_id_name, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'vpcs', vpc_id_name) + + # Inventory: Group by security group + if self.group_by_security_group: + try: + if instance.security_group: + key = self.to_safe("security_group_" + instance.security_group.name) + self.push(self.inventory, key, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'security_groups', key) + + except AttributeError: + self.fail_with_error('\n'.join(['Package boto seems a bit older.', + 'Please upgrade boto >= 2.3.0.'])) + # Inventory: Group by tag keys + if self.group_by_tag_keys: + for k, v in instance.tags.items(): + if self.expand_csv_tags and v and ',' in v: + values = map(lambda x: x.strip(), v.split(',')) + else: + values = [v] + + for v in values: + if v: + key = self.to_safe("tag_" + k + "=" + v) + else: + key = self.to_safe("tag_" + k) + self.push(self.inventory, key, hostname) + if self.nested_groups: + self.push_group(self.inventory, 'tags', self.to_safe("tag_" + k)) + if v: + self.push_group(self.inventory, self.to_safe("tag_" + k), key) + + # Inventory: Group by engine + if self.group_by_rds_engine: + self.push(self.inventory, self.to_safe("rds_" + instance.engine), hostname) + if self.nested_groups: + self.push_group(self.inventory, 'rds_engines', self.to_safe("rds_" + instance.engine)) + + # Inventory: Group by parameter group + if self.group_by_rds_parameter_group: + self.push(self.inventory, self.to_safe("rds_parameter_group_" + instance.parameter_group.name), hostname) + if self.nested_groups: + self.push_group(self.inventory, 'rds_parameter_groups', self.to_safe("rds_parameter_group_" + instance.parameter_group.name)) + + # Global Tag: instances without tags + if self.group_by_tag_none and len(instance.tags) == 0: + self.push(self.inventory, 'tag_none', hostname) + if self.nested_groups: + self.push_group(self.inventory, 'tags', 'tag_none') + + # Global Tag: all RDS instances + self.push(self.inventory, 'rds', hostname) + + self.inventory["_meta"]["hostvars"][hostname] = self.get_host_info_dict_from_instance(instance) + self.inventory["_meta"]["hostvars"][hostname]['ansible_host'] = dest + + def add_elasticache_cluster(self, cluster, region): + ''' Adds an ElastiCache cluster to the inventory and index, as long as + it's nodes are addressable ''' + + # Only want available clusters unless all_elasticache_clusters is True + if not self.all_elasticache_clusters and cluster['CacheClusterStatus'] != 'available': + return + + # Select the best destination address + if 'ConfigurationEndpoint' in cluster and cluster['ConfigurationEndpoint']: + # Memcached cluster + dest = cluster['ConfigurationEndpoint']['Address'] + is_redis = False + else: + # Redis sigle node cluster + # Because all Redis clusters are single nodes, we'll merge the + # info from the cluster with info about the node + dest = cluster['CacheNodes'][0]['Endpoint']['Address'] + is_redis = True + + if not dest: + # Skip clusters we cannot address (e.g. private VPC subnet) + return + + # Add to index + self.index[dest] = [region, cluster['CacheClusterId']] + + # Inventory: Group by instance ID (always a group of 1) + if self.group_by_instance_id: + self.inventory[cluster['CacheClusterId']] = [dest] + if self.nested_groups: + self.push_group(self.inventory, 'instances', cluster['CacheClusterId']) + + # Inventory: Group by region + if self.group_by_region and not is_redis: + self.push(self.inventory, region, dest) + if self.nested_groups: + self.push_group(self.inventory, 'regions', region) + + # Inventory: Group by availability zone + if self.group_by_availability_zone and not is_redis: + self.push(self.inventory, cluster['PreferredAvailabilityZone'], dest) + if self.nested_groups: + if self.group_by_region: + self.push_group(self.inventory, region, cluster['PreferredAvailabilityZone']) + self.push_group(self.inventory, 'zones', cluster['PreferredAvailabilityZone']) + + # Inventory: Group by node type + if self.group_by_instance_type and not is_redis: + type_name = self.to_safe('type_' + cluster['CacheNodeType']) + self.push(self.inventory, type_name, dest) + if self.nested_groups: + self.push_group(self.inventory, 'types', type_name) + + # Inventory: Group by VPC (information not available in the current + # AWS API version for ElastiCache) + + # Inventory: Group by security group + if self.group_by_security_group and not is_redis: + + # Check for the existence of the 'SecurityGroups' key and also if + # this key has some value. When the cluster is not placed in a SG + # the query can return None here and cause an error. + if 'SecurityGroups' in cluster and cluster['SecurityGroups'] is not None: + for security_group in cluster['SecurityGroups']: + key = self.to_safe("security_group_" + security_group['SecurityGroupId']) + self.push(self.inventory, key, dest) + if self.nested_groups: + self.push_group(self.inventory, 'security_groups', key) + + # Inventory: Group by engine + if self.group_by_elasticache_engine and not is_redis: + self.push(self.inventory, self.to_safe("elasticache_" + cluster['Engine']), dest) + if self.nested_groups: + self.push_group(self.inventory, 'elasticache_engines', self.to_safe(cluster['Engine'])) + + # Inventory: Group by parameter group + if self.group_by_elasticache_parameter_group: + self.push(self.inventory, self.to_safe("elasticache_parameter_group_" + cluster['CacheParameterGroup']['CacheParameterGroupName']), dest) + if self.nested_groups: + self.push_group(self.inventory, 'elasticache_parameter_groups', self.to_safe(cluster['CacheParameterGroup']['CacheParameterGroupName'])) + + # Inventory: Group by replication group + if self.group_by_elasticache_replication_group and 'ReplicationGroupId' in cluster and cluster['ReplicationGroupId']: + self.push(self.inventory, self.to_safe("elasticache_replication_group_" + cluster['ReplicationGroupId']), dest) + if self.nested_groups: + self.push_group(self.inventory, 'elasticache_replication_groups', self.to_safe(cluster['ReplicationGroupId'])) + + # Global Tag: all ElastiCache clusters + self.push(self.inventory, 'elasticache_clusters', cluster['CacheClusterId']) + + host_info = self.get_host_info_dict_from_describe_dict(cluster) + + self.inventory["_meta"]["hostvars"][dest] = host_info + + # Add the nodes + for node in cluster['CacheNodes']: + self.add_elasticache_node(node, cluster, region) + + def add_elasticache_node(self, node, cluster, region): + ''' Adds an ElastiCache node to the inventory and index, as long as + it is addressable ''' + + # Only want available nodes unless all_elasticache_nodes is True + if not self.all_elasticache_nodes and node['CacheNodeStatus'] != 'available': + return + + # Select the best destination address + dest = node['Endpoint']['Address'] + + if not dest: + # Skip nodes we cannot address (e.g. private VPC subnet) + return + + node_id = self.to_safe(cluster['CacheClusterId'] + '_' + node['CacheNodeId']) + + # Add to index + self.index[dest] = [region, node_id] + + # Inventory: Group by node ID (always a group of 1) + if self.group_by_instance_id: + self.inventory[node_id] = [dest] + if self.nested_groups: + self.push_group(self.inventory, 'instances', node_id) + + # Inventory: Group by region + if self.group_by_region: + self.push(self.inventory, region, dest) + if self.nested_groups: + self.push_group(self.inventory, 'regions', region) + + # Inventory: Group by availability zone + if self.group_by_availability_zone: + self.push(self.inventory, cluster['PreferredAvailabilityZone'], dest) + if self.nested_groups: + if self.group_by_region: + self.push_group(self.inventory, region, cluster['PreferredAvailabilityZone']) + self.push_group(self.inventory, 'zones', cluster['PreferredAvailabilityZone']) + + # Inventory: Group by node type + if self.group_by_instance_type: + type_name = self.to_safe('type_' + cluster['CacheNodeType']) + self.push(self.inventory, type_name, dest) + if self.nested_groups: + self.push_group(self.inventory, 'types', type_name) + + # Inventory: Group by VPC (information not available in the current + # AWS API version for ElastiCache) + + # Inventory: Group by security group + if self.group_by_security_group: + + # Check for the existence of the 'SecurityGroups' key and also if + # this key has some value. When the cluster is not placed in a SG + # the query can return None here and cause an error. + if 'SecurityGroups' in cluster and cluster['SecurityGroups'] is not None: + for security_group in cluster['SecurityGroups']: + key = self.to_safe("security_group_" + security_group['SecurityGroupId']) + self.push(self.inventory, key, dest) + if self.nested_groups: + self.push_group(self.inventory, 'security_groups', key) + + # Inventory: Group by engine + if self.group_by_elasticache_engine: + self.push(self.inventory, self.to_safe("elasticache_" + cluster['Engine']), dest) + if self.nested_groups: + self.push_group(self.inventory, 'elasticache_engines', self.to_safe("elasticache_" + cluster['Engine'])) + + # Inventory: Group by parameter group (done at cluster level) + + # Inventory: Group by replication group (done at cluster level) + + # Inventory: Group by ElastiCache Cluster + if self.group_by_elasticache_cluster: + self.push(self.inventory, self.to_safe("elasticache_cluster_" + cluster['CacheClusterId']), dest) + + # Global Tag: all ElastiCache nodes + self.push(self.inventory, 'elasticache_nodes', dest) + + host_info = self.get_host_info_dict_from_describe_dict(node) + + if dest in self.inventory["_meta"]["hostvars"]: + self.inventory["_meta"]["hostvars"][dest].update(host_info) + else: + self.inventory["_meta"]["hostvars"][dest] = host_info + + def add_elasticache_replication_group(self, replication_group, region): + ''' Adds an ElastiCache replication group to the inventory and index ''' + + # Only want available clusters unless all_elasticache_replication_groups is True + if not self.all_elasticache_replication_groups and replication_group['Status'] != 'available': + return + + # Skip clusters we cannot address (e.g. private VPC subnet or clustered redis) + if replication_group['NodeGroups'][0]['PrimaryEndpoint'] is None or \ + replication_group['NodeGroups'][0]['PrimaryEndpoint']['Address'] is None: + return + + # Select the best destination address (PrimaryEndpoint) + dest = replication_group['NodeGroups'][0]['PrimaryEndpoint']['Address'] + + # Add to index + self.index[dest] = [region, replication_group['ReplicationGroupId']] + + # Inventory: Group by ID (always a group of 1) + if self.group_by_instance_id: + self.inventory[replication_group['ReplicationGroupId']] = [dest] + if self.nested_groups: + self.push_group(self.inventory, 'instances', replication_group['ReplicationGroupId']) + + # Inventory: Group by region + if self.group_by_region: + self.push(self.inventory, region, dest) + if self.nested_groups: + self.push_group(self.inventory, 'regions', region) + + # Inventory: Group by availability zone (doesn't apply to replication groups) + + # Inventory: Group by node type (doesn't apply to replication groups) + + # Inventory: Group by VPC (information not available in the current + # AWS API version for replication groups + + # Inventory: Group by security group (doesn't apply to replication groups) + # Check this value in cluster level + + # Inventory: Group by engine (replication groups are always Redis) + if self.group_by_elasticache_engine: + self.push(self.inventory, 'elasticache_redis', dest) + if self.nested_groups: + self.push_group(self.inventory, 'elasticache_engines', 'redis') + + # Global Tag: all ElastiCache clusters + self.push(self.inventory, 'elasticache_replication_groups', replication_group['ReplicationGroupId']) + + host_info = self.get_host_info_dict_from_describe_dict(replication_group) + + self.inventory["_meta"]["hostvars"][dest] = host_info + + def get_route53_records(self): + ''' Get and store the map of resource records to domain names that + point to them. ''' + + if self.boto_profile: + r53_conn = route53.Route53Connection(profile_name=self.boto_profile) + else: + r53_conn = route53.Route53Connection() + all_zones = r53_conn.get_zones() + + route53_zones = [zone for zone in all_zones if zone.name[:-1] not in self.route53_excluded_zones] + + self.route53_records = {} + + for zone in route53_zones: + rrsets = r53_conn.get_all_rrsets(zone.id) + + for record_set in rrsets: + record_name = record_set.name + + if record_name.endswith('.'): + record_name = record_name[:-1] + + for resource in record_set.resource_records: + self.route53_records.setdefault(resource, set()) + self.route53_records[resource].add(record_name) + + def get_instance_route53_names(self, instance): + ''' Check if an instance is referenced in the records we have from + Route53. If it is, return the list of domain names pointing to said + instance. If nothing points to it, return an empty list. ''' + + instance_attributes = ['public_dns_name', 'private_dns_name', + 'ip_address', 'private_ip_address'] + + name_list = set() + + for attrib in instance_attributes: + try: + value = getattr(instance, attrib) + except AttributeError: + continue + + if value in self.route53_records: + name_list.update(self.route53_records[value]) + + return list(name_list) + + def get_host_info_dict_from_instance(self, instance): + instance_vars = {} + for key in vars(instance): + value = getattr(instance, key) + key = self.to_safe('ec2_' + key) + + # Handle complex types + # state/previous_state changed to properties in boto in https://github.com/boto/boto/commit/a23c379837f698212252720d2af8dec0325c9518 + if key == 'ec2__state': + instance_vars['ec2_state'] = instance.state or '' + instance_vars['ec2_state_code'] = instance.state_code + elif key == 'ec2__previous_state': + instance_vars['ec2_previous_state'] = instance.previous_state or '' + instance_vars['ec2_previous_state_code'] = instance.previous_state_code + elif isinstance(value, (int, bool)): + instance_vars[key] = value + elif isinstance(value, six.string_types): + instance_vars[key] = value.strip() + elif value is None: + instance_vars[key] = '' + elif key == 'ec2_region': + instance_vars[key] = value.name + elif key == 'ec2__placement': + instance_vars['ec2_placement'] = value.zone + elif key == 'ec2_tags': + for k, v in value.items(): + if self.expand_csv_tags and ',' in v: + v = list(map(lambda x: x.strip(), v.split(','))) + key = self.to_safe('ec2_tag_' + k) + instance_vars[key] = v + elif key == 'ec2_groups': + group_ids = [] + group_names = [] + for group in value: + group_ids.append(group.id) + group_names.append(group.name) + instance_vars["ec2_security_group_ids"] = ','.join([str(i) for i in group_ids]) + instance_vars["ec2_security_group_names"] = ','.join([str(i) for i in group_names]) + elif key == 'ec2_block_device_mapping': + instance_vars["ec2_block_devices"] = {} + for k, v in value.items(): + instance_vars["ec2_block_devices"][os.path.basename(k)] = v.volume_id + else: + pass + # TODO Product codes if someone finds them useful + # print key + # print type(value) + # print value + + instance_vars[self.to_safe('ec2_account_id')] = self.aws_account_id + + return instance_vars + + def get_host_info_dict_from_describe_dict(self, describe_dict): + ''' Parses the dictionary returned by the API call into a flat list + of parameters. This method should be used only when 'describe' is + used directly because Boto doesn't provide specific classes. ''' + + # I really don't agree with prefixing everything with 'ec2' + # because EC2, RDS and ElastiCache are different services. + # I'm just following the pattern used until now to not break any + # compatibility. + + host_info = {} + for key in describe_dict: + value = describe_dict[key] + key = self.to_safe('ec2_' + self.uncammelize(key)) + + # Handle complex types + + # Target: Memcached Cache Clusters + if key == 'ec2_configuration_endpoint' and value: + host_info['ec2_configuration_endpoint_address'] = value['Address'] + host_info['ec2_configuration_endpoint_port'] = value['Port'] + + # Target: Cache Nodes and Redis Cache Clusters (single node) + if key == 'ec2_endpoint' and value: + host_info['ec2_endpoint_address'] = value['Address'] + host_info['ec2_endpoint_port'] = value['Port'] + + # Target: Redis Replication Groups + if key == 'ec2_node_groups' and value: + host_info['ec2_endpoint_address'] = value[0]['PrimaryEndpoint']['Address'] + host_info['ec2_endpoint_port'] = value[0]['PrimaryEndpoint']['Port'] + replica_count = 0 + for node in value[0]['NodeGroupMembers']: + if node['CurrentRole'] == 'primary': + host_info['ec2_primary_cluster_address'] = node['ReadEndpoint']['Address'] + host_info['ec2_primary_cluster_port'] = node['ReadEndpoint']['Port'] + host_info['ec2_primary_cluster_id'] = node['CacheClusterId'] + elif node['CurrentRole'] == 'replica': + host_info['ec2_replica_cluster_address_' + str(replica_count)] = node['ReadEndpoint']['Address'] + host_info['ec2_replica_cluster_port_' + str(replica_count)] = node['ReadEndpoint']['Port'] + host_info['ec2_replica_cluster_id_' + str(replica_count)] = node['CacheClusterId'] + replica_count += 1 + + # Target: Redis Replication Groups + if key == 'ec2_member_clusters' and value: + host_info['ec2_member_clusters'] = ','.join([str(i) for i in value]) + + # Target: All Cache Clusters + elif key == 'ec2_cache_parameter_group': + host_info["ec2_cache_node_ids_to_reboot"] = ','.join([str(i) for i in value['CacheNodeIdsToReboot']]) + host_info['ec2_cache_parameter_group_name'] = value['CacheParameterGroupName'] + host_info['ec2_cache_parameter_apply_status'] = value['ParameterApplyStatus'] + + # Target: Almost everything + elif key == 'ec2_security_groups': + + # Skip if SecurityGroups is None + # (it is possible to have the key defined but no value in it). + if value is not None: + sg_ids = [] + for sg in value: + sg_ids.append(sg['SecurityGroupId']) + host_info["ec2_security_group_ids"] = ','.join([str(i) for i in sg_ids]) + + # Target: Everything + # Preserve booleans and integers + elif isinstance(value, (int, bool)): + host_info[key] = value + + # Target: Everything + # Sanitize string values + elif isinstance(value, six.string_types): + host_info[key] = value.strip() + + # Target: Everything + # Replace None by an empty string + elif value is None: + host_info[key] = '' + + else: + # Remove non-processed complex types + pass + + return host_info + + def get_host_info(self): + ''' Get variables about a specific host ''' + + if len(self.index) == 0: + # Need to load index from cache + self.load_index_from_cache() + + if self.args.host not in self.index: + # try updating the cache + self.do_api_calls_update_cache() + if self.args.host not in self.index: + # host might not exist anymore + return self.json_format_dict({}, True) + + (region, instance_id) = self.index[self.args.host] + + instance = self.get_instance(region, instance_id) + return self.json_format_dict(self.get_host_info_dict_from_instance(instance), True) + + def push(self, my_dict, key, element): + ''' Push an element onto an array that may not have been defined in + the dict ''' + group_info = my_dict.setdefault(key, []) + if isinstance(group_info, dict): + host_list = group_info.setdefault('hosts', []) + host_list.append(element) + else: + group_info.append(element) + + def push_group(self, my_dict, key, element): + ''' Push a group as a child of another group. ''' + parent_group = my_dict.setdefault(key, {}) + if not isinstance(parent_group, dict): + parent_group = my_dict[key] = {'hosts': parent_group} + child_groups = parent_group.setdefault('children', []) + if element not in child_groups: + child_groups.append(element) + + def get_inventory_from_cache(self): + ''' Reads the inventory from the cache file and returns it as a JSON + object ''' + + with open(self.cache_path_cache, 'r') as f: + json_inventory = f.read() + return json_inventory + + def load_index_from_cache(self): + ''' Reads the index from the cache file sets self.index ''' + + with open(self.cache_path_index, 'rb') as f: + self.index = json.load(f) + + def write_to_cache(self, data, filename): + ''' Writes data in JSON format to a file ''' + + json_data = self.json_format_dict(data, True) + with open(filename, 'w') as f: + f.write(json_data) + + def uncammelize(self, key): + temp = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', key) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', temp).lower() + + def to_safe(self, word): + ''' Converts 'bad' characters in a string to underscores so they can be used as Ansible groups ''' + regex = r"[^A-Za-z0-9\_" + if not self.replace_dash_in_groups: + regex += r"\-" + return re.sub(regex + "]", "_", word) + + def json_format_dict(self, data, pretty=False): + ''' Converts a dict to a JSON object and dumps it as a formatted + string ''' + + if pretty: + return json.dumps(data, sort_keys=True, indent=2) + else: + return json.dumps(data) + + +if __name__ == '__main__': + # Run the script + Ec2Inventory() \ No newline at end of file diff --git a/provisioning/group_vars/production/vars.yml b/provisioning/group_vars/production/vars.yml new file mode 100644 index 00000000..e4de58e7 --- /dev/null +++ b/provisioning/group_vars/production/vars.yml @@ -0,0 +1,60 @@ +--- +### Variables for Regluit Production Server ### +### Sensitive vars are references to actual values in vault.yml ### +### Use ansible-vault view vault.yml to see the secret values ### + +project_path: "/opt/regluit" +django_settings_module: "regluit.settings.prod" +virtualenv_name: "venv" +user_name: "ubuntu" +server_name: "m.unglue.it" + +wsgi_home: "/opt/regluit/venv" +wsgi_python_path: "/opt/regluit/venv/bin/python" + +# Branch to checkout +repo_version: "newfoundation" + +### Variables in settings.prod.py ### +mysql_db_name: "regluit" +mysql_db_user: "regluit" +mysql_db_pass: "password123" +mysql_db_host: "localhost" +mysql_db_port: 3306 +email_host: "{{ vault_email_host }}" +email_port: "{{ vault_email_port }}" +default_from_email: "notices@gluejar.com" +broker_transport: "redis" +broker_host: "localhost" +broker_port: 6379 +broker_vhost: "0" + +### Variables in common.py ### +common_keys: + booxtream_api_key: "{{ vault_booxtream_api_key }}" + booxtream_api_user: "{{ vault_booxtream_api_user }}" + dropbox_key: "{{ vault_dropbox_key }}" + github_public_token: "{{ vault_github_public_token }}" + mailchimp_api_key: "{{ vault_mailchimp_api_key }}" + mailchimp_news_id: "{{ vault_mailchimp_news_id }}" + mobigen_url: "{{ vault_mobigen_url }}" + mobigen_user_id: "{{ vault_mobigen_user_id }}" + mobigen_password: "{{ vault_mobigen_password }}" + +### Variables in host.py ### +host_keys: + secret_key: '{{ vault_secret_key }}' + google_books_api_key: "{{ vault_google_books_api_key }}" + goodreads_api_key: "{{ vault_goodreads_api_key }}" + goodreads_api_secret: "{{ vault_goodreads_api_secret }}" + email_host_user: '{{ vault_email_host_user }}' + email_host_password: '{{ vault_email_host_password }}' + social_auth_twitter_key: '{{ vault_social_auth_twitter_key }}' + social_auth_twitter_secret: '{{ vault_social_auth_twitter_secret }}' + social_auth_facebook_key: '{{ vault_social_auth_facebook_key }}' + social_auth_facebook_secret: '{{ vault_social_auth_facebook_secret }}' + social_auth_google_oauth2_key: '{{ vault_social_auth_google_oauth2_key }}' + social_auth_google_oauth2_secret: '{{ vault_social_auth_google_oauth2_secret }}' + aws_access_key_id: '{{ vault_aws_access_key_id }}' + aws_secret_access_key: '{{ vault_aws_secret_access_key }}' + aws_storage_bucket_name: '{{ vault_aws_storage_bucket_name }}' \ No newline at end of file diff --git a/provisioning/group_vars/production/vault.yml b/provisioning/group_vars/production/vault.yml new file mode 100644 index 00000000..8be63f37 --- /dev/null +++ b/provisioning/group_vars/production/vault.yml @@ -0,0 +1,92 @@ +$ANSIBLE_VAULT;1.1;AES256 +36653766626632633437383061323964393266313432373930623833333534336239323666336565 +3565323337323164646362303335353830646330666130300a366661323362356164343366613265 +35383637336431323965373730653539356530643839373866663330373066313337616330653966 +3939363433663434620a323761336338393463303230363931366130393866653462383561343234 +65383838626238366239326665306237373632666635653533333330643738326235643335663932 +33643238613365636233383437663262663466333463353938316166626130373663323864393665 +39646639393832383133373166373539343563343363633261646362373530643161646563396336 +35336362653339656231376166356463666361336437636431636663633530623036656131663035 +61656631626637313837646434356363373931336130626336363964656434366636616432303031 +63366532343463663732353330613264633734366162326631356631616161303238323062613035 +31373532646437316130333461636538333166346237323561323633333363373038323564316262 +30666666663966313332313561373236666636363366313631343730376362393833663739343630 +61313133393631323534623962633830343766316566613039323263643436626665393462626531 +34366232656535316533363234383466663335346465386333383563626131383032346434653639 +35656663613163383262643661306635633733336261613739316232636334373965353261663333 +61333338623039343166333339613464656663643765643236353561626331643134363661393631 +33343134376161333230326261656531386635643165653966393631636361663631353639353036 +64393336643364333239333830333166626638643031666237383466623563653336613763336434 +37383137643264616162373138313431393534376633333938383161663736633236303631666365 +30383430326430613131353839376162363839636364363865376231336336386232353333656135 +31336231366236386532633563663432383334336563323862393330343133346135336332303832 +38386232303036656164363963623363393063353437363031623638386336373363623765393636 +31303230666136366164623835366463316436363633303563386533623431313035323564626164 +38353166333038633634396534363137626536623862376231643332633762383065613161343538 +62646565396530623931653031626331383163333332373637393661353236396662363133326637 +35623531366239363336313164623035353339623265323734393437336137366330396362623664 +33366639666161373666663035373537656364313534663137316165363862623630643933353437 +31303131353063656139366466376564393230613235396333343230313639353734343731376333 +38636235306535316361663433333462383637633435306432623833396435356263663235373262 +64316462383064653733396633376564646665343432616231646332393032383463656263376338 +64303836366236613865353137366333643334313764383538633832363532346334663734633130 +65333664666163363838613063663139306435613038653133396363353532343865376462393835 +61366539383731613430636132306130626466306334343035646436336230376434383633326436 +36343338653961613566636230326665653733666139303537623531363439613931316331633131 +63663234663664343031326462326464393532363364383332626263616132386434333665303132 +36336332633030313061666637643532393833353465656531663939636538623864316561353266 +36366162343962383964396163653865633164363262373833383931373537623865373466626666 +66613466623734633131626161356136363864656366346437393638306431623531306133643861 +66303066633566653733386466326635303463383262626664643162323839323239303661316330 +37393634346166633730393038636234326338386565613461656636343837393934303666633836 +37663061633761636361316562383733623265373863363066383634356633383132623366643237 +37623430643933393663353130613933396331363336626530383364373432613436333633646537 +37643231353364333962616138386239366634356430303637323466346662633965346365653935 +32303763363631653037666634366165363739373436356562396565363438386538353730366634 +61613262633134323735353165363738336363626136306665613530306532386565336537303137 +30653364626233663165316263633466326638313166383539306437396139343863656337663161 +66303036326264353637646330323230616264343034303630323334363632353963303739383262 +33396331306631323065363334323633623461613934633932303962333965653564313164376530 +35613539376434373265663563326436653439323866326235313562643239303237373931656363 +64306533396261626562323838613236623031353932383638636565323035623566383063313663 +38656665663065346136666433373361373562626233333863633964346535366234643430336135 +61613439303030663339363436343462373531356165366433303437613961376137326236333139 +36336238376261336538663933306539313737333033633039626230336336383165346664323565 +64626334656663396462396134313634333362363537663566663137363863636434366361306364 +64316563616135616264316431396365353037316433313364653461616466303563626461353633 +63346238383964333533386264613637663865373833656334303938663661613035356335663036 +62326630646330396135313931366631323362653031623034623239386162383663376135653537 +38336165376365666166623937663930653636666230323565653966303361393436373637623833 +35663333613531623837336663373863616431343434373337626230646261366333666232626263 +36393130303739363834643737383532626536623662356539373264363730396639643864633931 +37313038343732653731383262353637386464396435356561656137613835656465306464626436 +66383837376236363965666237396534376566623536393437633031336461393666336466613962 +62656337356331366233316537626665633264666637633433303130653736343033313830326131 +31396531356139653466376661663961626637316130316661653963653938646362343862653136 +62303664623938313863636238636532376566303863633861663035333834303966636263636532 +64386539643230366139303961326230633366336534656536323463313366626137353261666539 +30333265653361643230643337616131663339373630663464656438373434363431356661343131 +37386435633137316538623964643731643936643562656565386164653032356530353166316437 +34346637336430373566366232323166386132383962616165633239366237646238366236343862 +34633733396635333762616436656365346232393637366630386634376636366531363535633032 +35303232636239663734396632363163366133396237646661346466303464323937323164663838 +35376661643662343932316635356631653865633765663035396366396666353965646365396236 +66633162323830653162306339383437363463663130633531336662303162663861323337396133 +36646363323438313337313031623330323230313063373634366162653533646365353864336233 +65653335333436316363393866303763353365386333326662353166333230316336353761343833 +32376435376237303966366230396232303236626361366637323666303732303934643231373630 +62313563633865336532616438396562363337306332643236333861616162353761666162636262 +63393464353166633666366466616465323531396366303337306262653339373435633135613436 +65323062623361326465313636663732346665323261383730313131636130626566363433623733 +62656637353564336237333139303338396262306462643337316163356638356365343838643030 +62613538363765613638643439333034653830653464663364613464346339643136353239393263 +33333766363137306365616230343963646338353263663964653739663239646232666233306339 +65336366306139363038333034313364633637366133303931613030313733343966323161353563 +62306134626166633339336139393630336166666637373364643037343232333035353830346136 +38623139326536386130363034333831393961316261643531313335316261396266666561356633 +31366636343733616230306563666239643134666363343831363731663439396234656365363535 +66363935356633303166316635663239313338333335623931663234616334373536616634363739 +62343739353733336663336535376161376132326462306166353963303030633764343663646261 +36376131663764313339316330316638653331376139616635363461623036386434373564323334 +63336465623166343261363262636665363838383866393234343631663136303265313430386432 +616437326539303165323962636534633063 diff --git a/provisioning/hosts b/provisioning/hosts new file mode 100644 index 00000000..58f71868 --- /dev/null +++ b/provisioning/hosts @@ -0,0 +1,2 @@ +[production] +regluit-prod ansible_host=ec2-18-206-73-169.compute-1.amazonaws.com ansible_user=ubuntu \ No newline at end of file diff --git a/provisioning/roles/regluit_common/defaults/main.yml b/provisioning/roles/regluit_common/defaults/main.yml new file mode 100644 index 00000000..a1f9926f --- /dev/null +++ b/provisioning/roles/regluit_common/defaults/main.yml @@ -0,0 +1,21 @@ +project_path: "/opt/regluit" +django_settings_module: "regluit.settings.me" +virtualenv_name: "venv" + +# MySQL +mysql_db_name: "regluit" +mysql_db_user: "regluit" +mysql_db_pass: "password123" +mysql_db_host: "localhost" +mysql_db_port: 3306 + +# Task Broker +broker_transport: "redis" +broker_host: "localhost" +broker_port: 6379 +broker_vhost: "0" + +# Common.py defaults +boxstream_api_key: "012345678901234567890123456789" +boxstream_api_user: "user" +dropbox_key: "012345678901234" diff --git a/provisioning/roles/regluit_common/files/celerybeat b/provisioning/roles/regluit_common/files/celerybeat new file mode 100644 index 00000000..34b9ad6a --- /dev/null +++ b/provisioning/roles/regluit_common/files/celerybeat @@ -0,0 +1,154 @@ +#!/bin/bash +# ========================================================= +# celerybeat - Starts the Celery periodic task scheduler. +# ========================================================= +# +# :Usage: /etc/init.d/celerybeat {start|stop|force-reload|restart|try-restart|status} +# :Configuration file: /etc/default/celerybeat or /etc/default/celeryd +# +# See http://docs.celeryq.org/en/latest/cookbook/daemonizing.html#init-script-celerybeat +# This file is copied from https://github.com/ask/celery/blob/2.4/contrib/generic-init.d/celerybeat + +### BEGIN INIT INFO +# Provides: celerybeat +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $network $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: celery periodic task scheduler +### END INIT INFO + +# Cannot use set -e/bash -e since the kill -0 command will abort +# abnormally in the absence of a valid process ID. +#set -e + +DEFAULT_PID_FILE="/var/run/celerybeat.pid" +DEFAULT_LOG_FILE="/var/log/celerybeat.log" +DEFAULT_LOG_LEVEL="INFO" +DEFAULT_CELERYBEAT="celerybeat" + +# /etc/init.d/ssh: start and stop the celery task worker daemon. + +if test -f /etc/default/celeryd; then + . /etc/default/celeryd +fi + +if test -f /etc/default/celerybeat; then + . /etc/default/celerybeat +fi + +CELERYBEAT=${CELERYBEAT:-$DEFAULT_CELERYBEAT} +CELERYBEAT_PID_FILE=${CELERYBEAT_PID_FILE:-${CELERYBEAT_PIDFILE:-$DEFAULT_PID_FILE}} +CELERYBEAT_LOG_FILE=${CELERYBEAT_LOG_FILE:-${CELERYBEAT_LOGFILE:-$DEFAULT_LOG_FILE}} +CELERYBEAT_LOG_LEVEL=${CELERYBEAT_LOG_LEVEL:-${CELERYBEAT_LOGLEVEL:-$DEFAULT_LOG_LEVEL}} + +export CELERY_LOADER + +CELERYBEAT_OPTS="$CELERYBEAT_OPTS -f $CELERYBEAT_LOG_FILE -l $CELERYBEAT_LOG_LEVEL" + +if [ -n "$2" ]; then + CELERYBEAT_OPTS="$CELERYBEAT_OPTS $2" +fi + +CELERYBEAT_LOG_DIR=`dirname $CELERYBEAT_LOG_FILE` +CELERYBEAT_PID_DIR=`dirname $CELERYBEAT_PID_FILE` +if [ ! -d "$CELERYBEAT_LOG_DIR" ]; then + mkdir -p $CELERYBEAT_LOG_DIR +fi +if [ ! -d "$CELERYBEAT_PID_DIR" ]; then + mkdir -p $CELERYBEAT_PID_DIR +fi + +# Extra start-stop-daemon options, like user/group. +if [ -n "$CELERYBEAT_USER" ]; then + DAEMON_OPTS="$DAEMON_OPTS --uid $CELERYBEAT_USER" + chown "$CELERYBEAT_USER" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR +fi +if [ -n "$CELERYBEAT_GROUP" ]; then + DAEMON_OPTS="$DAEMON_OPTS --gid $CELERYBEAT_GROUP" + chgrp "$CELERYBEAT_GROUP" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR +fi + +CELERYBEAT_CHDIR=${CELERYBEAT_CHDIR:-$CELERYD_CHDIR} +if [ -n "$CELERYBEAT_CHDIR" ]; then + DAEMON_OPTS="$DAEMON_OPTS --workdir $CELERYBEAT_CHDIR" +fi + + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + +check_dev_null() { + if [ ! -c /dev/null ]; then + echo "/dev/null is not a character device!" + exit 1 + fi +} + +wait_pid () { + pid=$1 + forever=1 + i=0 + while [ $forever -gt 0 ]; do + kill -0 $pid 1>/dev/null 2>&1 + if [ $? -eq 1 ]; then + echo "OK" + forever=0 + else + kill -TERM "$pid" + i=$((i + 1)) + if [ $i -gt 60 ]; then + echo "ERROR" + echo "Timed out while stopping (30s)" + forever=0 + else + sleep 0.5 + fi + fi + done +} + + +stop_beat () { + echo -n "Stopping celerybeat... " + if [ -f "$CELERYBEAT_PID_FILE" ]; then + wait_pid $(cat "$CELERYBEAT_PID_FILE") + else + echo "NOT RUNNING" + fi +} + +start_beat () { + echo "Starting celerybeat..." + if [ -n "$VIRTUALENV" ]; then + source $VIRTUALENV/bin/activate + fi + $CELERYBEAT $CELERYBEAT_OPTS $DAEMON_OPTS --detach \ + --pidfile="$CELERYBEAT_PID_FILE" +} + + + +case "$1" in + start) + check_dev_null + start_beat + ;; + stop) + stop_beat + ;; + reload|force-reload) + echo "Use start+stop" + ;; + restart) + echo "Restarting celery periodic task scheduler" + stop_beat + check_dev_null + start_beat + ;; + + *) + echo "Usage: /etc/init.d/celerybeat {start|stop|restart}" + exit 1 +esac + +exit 0 \ No newline at end of file diff --git a/provisioning/roles/regluit_common/files/celeryd b/provisioning/roles/regluit_common/files/celeryd new file mode 100644 index 00000000..12ff8445 --- /dev/null +++ b/provisioning/roles/regluit_common/files/celeryd @@ -0,0 +1,217 @@ +#!/bin/bash +# ============================================ +# celeryd - Starts the Celery worker daemon. +# ============================================ +# +# :Usage: /etc/init.d/celeryd {start|stop|force-reload|restart|try-restart|status} +# +# :Configuration file: /etc/default/celeryd +# +# To configure celeryd you probably need to tell it where to chdir. +# +# EXAMPLE CONFIGURATION +# ===================== +# +# this is an example configuration for a Python project: +# +# /etc/default/celeryd: +# +# # List of nodes to start +# CELERYD_NODES="worker1 worker2 worker3"k +# # ... can also be a number of workers +# CELERYD_NODES=3 +# +# # Where to chdir at start. +# CELERYD_CHDIR="/opt/Myproject/" +# +# # Extra arguments to celeryd +# CELERYD_OPTS="--time-limit=300" +# +# # Name of the celery config module.# +# CELERY_CONFIG_MODULE="celeryconfig" +# +# EXAMPLE DJANGO CONFIGURATION +# ============================ +# +# # Where the Django project is. +# CELERYD_CHDIR="/opt/Project/" +# +# # Name of the projects settings module. +# export DJANGO_SETTINGS_MODULE="settings" +# +# # Path to celeryd +# CELERYD="/opt/Project/manage.py celeryd" +# +# AVAILABLE OPTIONS +# ================= +# +# * CELERYD_NODES +# +# A space separated list of nodes, or a number describing the number of +# nodes, to start +# +# * CELERYD_OPTS +# Additional arguments to celeryd-multi, see `celeryd-multi --help` +# and `celeryd --help` for help. +# +# * CELERYD_CHDIR +# Path to chdir at start. Default is to stay in the current directory. +# +# * CELERYD_PIDFILE +# Full path to the pidfile. Default is /var/run/celeryd.pid. +# +# * CELERYD_LOGFILE +# Full path to the celeryd logfile. Default is /var/log/celeryd.log +# +# * CELERYD_LOG_LEVEL +# Log level to use for celeryd. Default is INFO. +# +# * CELERYD +# Path to the celeryd program. Default is `celeryd`. +# You can point this to an virtualenv, or even use manage.py for django. +# +# * CELERYD_USER +# User to run celeryd as. Default is current user. +# +# * CELERYD_GROUP +# Group to run celeryd as. Default is current user. + +# VARIABLE EXPANSION +# ================== +# +# The following abbreviations will be expanded +# +# * %n -> node name +# * %h -> host name + + +### BEGIN INIT INFO +# Provides: celeryd +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $network $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: celery task worker daemon +### END INIT INFO + +#set -e + +DEFAULT_PID_FILE="/var/run/celeryd@%n.pid" +DEFAULT_LOG_FILE="/var/log/celeryd@%n.log" +DEFAULT_LOG_LEVEL="INFO" +DEFAULT_NODES="celery" +DEFAULT_CELERYD="-m celery.bin.celeryd_detach" + +# /etc/init.d/celeryd: start and stop the celery task worker daemon. + +CELERY_DEFAULTS=${CELERY_DEFAULTS:-"/etc/default/celeryd"} + +test -f "$CELERY_DEFAULTS" && . "$CELERY_DEFAULTS" +if [ -f "/etc/default/celeryd" ]; then + . /etc/default/celeryd +fi + +if [ -f $VIRTUALENV_ACTIVATE ]; then + echo "activating virtualenv $VIRTUALENV_ACTIVATE" + source "$VIRTUALENV_ACTIVATE" +fi + +CELERYD_PID_FILE=${CELERYD_PID_FILE:-${CELERYD_PIDFILE:-$DEFAULT_PID_FILE}} +CELERYD_LOG_FILE=${CELERYD_LOG_FILE:-${CELERYD_LOGFILE:-$DEFAULT_LOG_FILE}} +CELERYD_LOG_LEVEL=${CELERYD_LOG_LEVEL:-${CELERYD_LOGLEVEL:-$DEFAULT_LOG_LEVEL}} +CELERYD_MULTI=${CELERYD_MULTI:-"celeryd-multi"} +CELERYD=${CELERYD:-$DEFAULT_CELERYD} +CELERYD_NODES=${CELERYD_NODES:-$DEFAULT_NODES} + +export CELERY_LOADER + +if [ -n "$2" ]; then + CELERYD_OPTS="$CELERYD_OPTS $2" +fi + +# Extra start-stop-daemon options, like user/group. +if [ -n "$CELERYD_USER" ]; then + DAEMON_OPTS="$DAEMON_OPTS --uid=$CELERYD_USER" +fi +if [ -n "$CELERYD_GROUP" ]; then + DAEMON_OPTS="$DAEMON_OPTS --gid=$CELERYD_GROUP" +fi + +if [ -n "$CELERYD_CHDIR" ]; then + DAEMON_OPTS="$DAEMON_OPTS --workdir=\"$CELERYD_CHDIR\"" +fi + + +check_dev_null() { + if [ ! -c /dev/null ]; then + echo "/dev/null is not a character device!" + exit 1 + fi +} + + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + + +stop_workers () { + $CELERYD_MULTI stop $CELERYD_NODES --pidfile="$CELERYD_PID_FILE" +} + + +start_workers () { + $CELERYD_MULTI start $CELERYD_NODES $DAEMON_OPTS \ + --pidfile="$CELERYD_PID_FILE" \ + --logfile="$CELERYD_LOG_FILE" \ + --loglevel="$CELERYD_LOG_LEVEL" \ + --cmd="$CELERYD" \ + $CELERYD_OPTS +} + + +restart_workers () { + $CELERYD_MULTI restart $CELERYD_NODES $DAEMON_OPTS \ + --pidfile="$CELERYD_PID_FILE" \ + --logfile="$CELERYD_LOG_FILE" \ + --loglevel="$CELERYD_LOG_LEVEL" \ + --cmd="$CELERYD" \ + $CELERYD_OPTS +} + + + +case "$1" in + start) + check_dev_null + start_workers + ;; + + stop) + check_dev_null + stop_workers + ;; + + reload|force-reload) + echo "Use restart" + ;; + + status) + celeryctl status + ;; + + restart) + check_dev_null + restart_workers + ;; + + try-restart) + check_dev_null + restart_workers + ;; + + *) + echo "Usage: /etc/init.d/celeryd {start|stop|restart|try-restart|kill}" + exit 1 + ;; +esac + +exit 0 diff --git a/provisioning/roles/regluit_common/tasks/celery.yml b/provisioning/roles/regluit_common/tasks/celery.yml new file mode 100644 index 00000000..c2f52036 --- /dev/null +++ b/provisioning/roles/regluit_common/tasks/celery.yml @@ -0,0 +1,37 @@ +--- +# Tasks for Celeryd and Celerybeat processes +- name: Create /var/log/celery + become: true + file: + path: "/var/log/celery" + state: directory + #owner: celery + #group: celery + mode: 0775 + +- name: Create /var/run/celery + become: true + file: + path: "/var/run/celery" + state: directory + #owner: celery + #group: celery + mode: 0775 + +- name: Copy celery init.d scripts + become: true + copy: + src: "{{ item }}" + dest: "/etc/init.d/{{ item }}" + with_items: + - 'celeryd' + - 'celerybeat' + +- name: Copy celery config files + become: true + template: + src: "celery/{{ item }}.j2" + dest: "/etc/default/{{ item }}" + with_items: + - 'celeryd' + - 'celerybeat' diff --git a/provisioning/roles/regluit_common/tasks/main.yml b/provisioning/roles/regluit_common/tasks/main.yml new file mode 100644 index 00000000..84350481 --- /dev/null +++ b/provisioning/roles/regluit_common/tasks/main.yml @@ -0,0 +1,85 @@ +--- +# Need to install python2.7 and pip first so Ansible will function +# This is due to Ubuntu 16 shipping with Python3 by default +- name: Install python2.7 and pip + become: true + raw: bash -c "apt -qqy update && apt install -qqy python2.7-dev python-pip" + register: output + changed_when: output.stdout != "" + +- name: Gathering Facts + setup: + +- name: Install base regluit dependencies + become: true + apt: + name: "{{ item }}" + update_cache: true + state: present + with_items: + - 'git' + - 'python-setuptools' + - 'python-lxml' + - 'build-essential' + - 'libssl-dev' + - 'libffi-dev' + - 'libxml2-dev' + - 'libxslt-dev' + - 'mysql-server' + - 'mysql-client' + - 'libmysqlclient-dev' + - 'python-mysqldb' + +- name: Install virtualenv + pip: + name: "virtualenv" + state: present + +- name: Install python packages to virtualenv + pip: + requirements: "{{ project_path }}/requirements_versioned.pip" + state: present + virtualenv: "{{ project_path }}/venv" + +- name: Add project to PYTHONPATH of virtualenv + template: + src: "{{ item }}.j2" + dest: "{{ project_path }}/venv/lib/python2.7/site-packages/{{ item }}" + with_items: + - 'regluit.pth' + - 'opt.pth' + +- name: Create keys directory + file: + path: "{{ project_path}}/settings/keys" + state: directory + +- name: Copy keys files + copy: + src: "{{ project_path }}/settings/dummy/__init__.py" + dest: "{{ project_path }}/settings/keys/__init__.py" + remote_src: yes + +- name: Copy django settings template + template: + src: me.py.j2 + dest: "{{ project_path }}/settings/me.py" + +- name: Copy key templates to keys directory + template: + src: "{{ item }}.j2" + dest: "{{ project_path }}/settings/keys/{{ item }}" + with_items: + - 'common.py' + - 'host.py' + +- name: MySQL setup + become: true + import_tasks: mysql.yml + +- name: Redis setup + become: true + import_tasks: redis.yml + +# - name: Celery setup +# import_tasks: celery.yml diff --git a/provisioning/roles/regluit_common/tasks/mysql.yml b/provisioning/roles/regluit_common/tasks/mysql.yml new file mode 100644 index 00000000..ca5f6171 --- /dev/null +++ b/provisioning/roles/regluit_common/tasks/mysql.yml @@ -0,0 +1,12 @@ +--- +- name: Create MySQL database + mysql_db: + name: "{{ mysql_db_name }}" + state: present + +- name: Create MySQL user + mysql_user: + name: "{{ mysql_db_user }}" + password: "{{ mysql_db_pass }}" + priv: '*.*:ALL' + state: present diff --git a/provisioning/roles/regluit_common/tasks/redis.yml b/provisioning/roles/regluit_common/tasks/redis.yml new file mode 100644 index 00000000..ca646847 --- /dev/null +++ b/provisioning/roles/regluit_common/tasks/redis.yml @@ -0,0 +1,13 @@ +--- +- name: Install Redis server + become: yes + apt: + name: "redis-server" + state: present + +- name: Ensure Redis is started + become: yes + service: + name: "redis-server" + state: started + enabled: yes diff --git a/provisioning/roles/regluit_common/templates/celery/celerybeat.j2 b/provisioning/roles/regluit_common/templates/celery/celerybeat.j2 new file mode 100644 index 00000000..d459ad8b --- /dev/null +++ b/provisioning/roles/regluit_common/templates/celery/celerybeat.j2 @@ -0,0 +1,35 @@ +# http://docs.celeryproject.org/en/latest/cookbook/daemonizing.html#generic-initd-celerybeat-example +# to be placed at /etc/defaults/celerybeat + +# Where to chdir at start. +CELERYBEAT_CHDIR="{{ project_path }}t/" + +# Extra arguments to celerybeat +#CELERYBEAT_OPTS="--schedule=/var/run/celerybeat-schedule" + +# Name of the celery config module.# +CELERY_CONFIG_MODULE="celeryconfig" + +# Name of the projects settings module. +export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}" + +# Path to celerybeat +CELERYBEAT="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celerybeat" + +# virtualenv to use +VIRTUALENV="{{ project_path }}/{{ virtualenv_name }}" + +#Full path to the PID file. Default is /var/run/celeryd.pid +CELERYBEAT_PIDFILE="/var/log/celerybeat/celerybeat.pid" + +#Full path to the celeryd log file. Default is /var/log/celeryd.log +CELERYBEAT_LOGFILE="/var/log/celerybeat/celerybeat.log" + +#Log level to use for celeryd. Default is INFO. +CELERYBEAT_LOG_LEVEL="INFO" + +#User to run celeryd as. Default is current user. +#CELERYBEAT_USER + +#Group to run celeryd as. Default is current user. +#CELERYBEAT_GROUP diff --git a/provisioning/roles/regluit_common/templates/celery/celeryd.j2 b/provisioning/roles/regluit_common/templates/celery/celeryd.j2 new file mode 100644 index 00000000..c918efb4 --- /dev/null +++ b/provisioning/roles/regluit_common/templates/celery/celeryd.j2 @@ -0,0 +1,9 @@ +CELERYD_NODES="w1" +CELERYD_CHDIR="{{ project_path }}/" +CELERYD_LOG_FILE="/var/log/celery/%n.log" +CELERYD_PID_FILE="/var/log/celery/%n.pid" +CELERYD="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd" +CELERYD_MULTI="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd_multi" + +VIRTUALENV_ACTIVATE="{{ project_path }}/{{ virtualenv_name }}/bin/activate" +export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}" diff --git a/provisioning/roles/regluit_common/templates/common.py.j2 b/provisioning/roles/regluit_common/templates/common.py.j2 new file mode 100644 index 00000000..d835f1c8 --- /dev/null +++ b/provisioning/roles/regluit_common/templates/common.py.j2 @@ -0,0 +1,13 @@ +import os + +# all the COMMON_KEYS +# copy this file to settings/keys/ and replace the dummy values with real ones +BOOXTREAM_API_KEY = os.environ.get('BOOXTREAM_API_KEY', '{{ boxstream_api_key }}') +BOOXTREAM_API_USER = os.environ.get('BOOXTREAM_API_USER', '{{ boxstream_api_user }}') +DROPBOX_KEY = os.environ.get('DROPBOX_KEY', '{{ dropbox_key }}') +GITHUB_PUBLIC_TOKEN = os.environ.get('GITHUB_PUBLIC_TOKEN', None) # 40 chars; null has lower limit +MAILCHIMP_API_KEY = os.environ.get('MAILCHIMP_API_KEY', '-us2') # [32chars]-xx# +MAILCHIMP_NEWS_ID = os.environ.get('MAILCHIMP_NEWS_ID', '0123456789') +MOBIGEN_PASSWORD = os.environ.get('MOBIGEN_PASSWORD', '012345678901234') +MOBIGEN_URL = os.environ.get('MOBIGEN_URL', '') # https://host/mobigen +MOBIGEN_USER_ID = os.environ.get('MOBIGEN_USER_ID', 'user') diff --git a/provisioning/roles/regluit_common/templates/host.py.j2 b/provisioning/roles/regluit_common/templates/host.py.j2 new file mode 100644 index 00000000..9819dc7f --- /dev/null +++ b/provisioning/roles/regluit_common/templates/host.py.j2 @@ -0,0 +1,47 @@ +# host.py +# copy this file to settings/keys/ and replace the dummy values with real ones +# or generate it from the ansible vault +import os + +# you can use this to generate a key: http://www.miniwebtool.com/django-secret-key-generator/ +SECRET_KEY = os.environ.get("SECRET_KEY", '01234567890123456789012345678901234567890123456789') + +# you'll need to register a GoogleBooks API key +# https://code.google.com/apis/console +GOOGLE_BOOKS_API_KEY = os.environ.get("GOOGLE_BOOKS_API_KEY", "012345678901234567890123456789012345678") + +# +GOODREADS_API_KEY = os.environ.get("GOODREADS_API_KEY", "01234567890123456789") +GOODREADS_API_SECRET = os.environ.get("GOODREADS_API_SECRET", None) #43 chars + +# Amazon SES +# create with https://console.aws.amazon.com/ses/home?region=us-east-1#smtp-settings: +EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", '01234567890123456789') +EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", '01234567890123456789012345678901234567890123') + +# twitter auth +# you'll need to create a new Twitter application to fill in these blanks +# https://dev.twitter.com/apps/new +SOCIAL_AUTH_TWITTER_KEY = os.environ.get("SOCIAL_AUTH_TWITTER_KEY", '0123456789012345678901234') +SOCIAL_AUTH_TWITTER_SECRET = os.environ.get("SOCIAL_AUTH_TWITTER_SECRET", '01234567890123456789012345678901234567890123456789') + +# support@icontact.nl +BOOXTREAM_API_KEY = os.environ.get("BOOXTREAM_API_KEY", None) # 30 chars +BOOXTREAM_API_USER = os.environ.get("BOOXTREAM_API_USER", 'user') + +# you'll need to create a new Facebook application to fill in these blanks +# https://developers.facebook.com/apps/ +SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get("SOCIAL_AUTH_FACEBOOK_KEY", '012345678901234') +SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get("SOCIAL_AUTH_FACEBOOK_SECRET", '01234567890123456789012345678901') + +# https://console.developers.google.com/apis/credentials/oauthclient/ +# unglue.it (prod) SOCIAL_AUTH_GOOGLE_OAUTH2_KEY #2 +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get("_KEY", '012345678901-01234567890123456789012345678901.apps.googleusercontent.com') +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get("_SECRET", '012345678901234567890123') + +AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", '01234567890123456789') +AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", '') # 40 chars + +DATABASE_USER = os.environ.get("DATABASE_USER", 'root') +DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD", '') +DATABASE_HOST = os.environ.get("DATABASE_HOST", '') diff --git a/provisioning/roles/regluit_common/templates/me.py.j2 b/provisioning/roles/regluit_common/templates/me.py.j2 new file mode 100644 index 00000000..b82ede1b --- /dev/null +++ b/provisioning/roles/regluit_common/templates/me.py.j2 @@ -0,0 +1,90 @@ +# coding=utf-8 +from .common import * +try: + from .keys.host import * +except ImportError: + from .dummy.host import * + +DEBUG = True +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG + +# if you're doing development work, you'll want this to be zero +IS_PREVIEW = False + +# SITE_ID for your particular site -- must be configured in /core/fixtures/initial_data.json +SITE_ID = 3 + +ADMINS = ( + ('Raymond Yee', 'rdhyee+ungluebugs@gluejar.com'), + ('Eric Hellman', 'eric@gluejar.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': '{{ mysql_db_name }}', + 'USER': '{{ mysql_db_user }}', + 'PASSWORD': '{{ mysql_db_pass }}', + 'HOST': '{{ mysql_db_host }}', + 'PORT': '{{ mysql_db_port }} ', + 'TEST_CHARSET': 'utf8', + } +} + +STATIC_ROOT = '/var/www/static' +CKEDITOR_UPLOAD_PATH = '/var/www/static/media/' + + +TIME_ZONE = 'America/New_York' + +# settings for outbout email +# if you have a gmail account you can use your email address and password + +EMAIL_USE_TLS = True +EMAIL_HOST = 'smtp.gmail.com' +# EMAIL_HOST_USER is in keys/host +# EMAIL_HOST_PASSWORD is in keys/host +EMAIL_PORT = 587 +DEFAULT_FROM_EMAIL = 'info@ebookfoundation.org' + +# for use with test google account only +GOOGLE_DISPLAY_NAME = 'Unglue.It' +REDIRECT_IS_HTTPS = False + + +#BASE_URL = 'http://0.0.0.0' +BASE_URL_SECURE = 'https://0.0.0.0' + +# use redis as queuing service +BROKER_TRANSPORT = "{{ broker_transport }}" +BROKER_HOST = "{{ broker_host }}" +BROKER_PORT = {{ broker_port }} +BROKER_VHOST = "{{ broker_vhost }}" + +# send celery log to Python logging +CELERYD_HIJACK_ROOT_LOGGER = False + +# a debug_toolbar setting +INTERNAL_IPS = ('127.0.0.1',) + +CELERYD_LOG_LEVEL = "INFO" + +# decide which of the period tasks to add to the schedule +#CELERYBEAT_SCHEDULE['send_test_email'] = SEND_TEST_EMAIL_JOB +#CELERYBEAT_SCHEDULE['refresh_acqs'] = REFRESH_ACQS_JOB + +# if you're doing development work, you'll want this to be zero +IS_PREVIEW = False + +# username, password to pass to LIVE_SERVER_TEST_URL + +UNGLUEIT_TEST_USER = None +UNGLUEIT_TEST_PASSWORD = None + +# local settings for maintenance mode +MAINTENANCE_MODE = False + +# assume that CSS will get generated on dev +SASS_OUTPUT_STYLE = 'compressed' diff --git a/provisioning/roles/regluit_common/templates/opt.pth.j2 b/provisioning/roles/regluit_common/templates/opt.pth.j2 new file mode 100644 index 00000000..27d47a41 --- /dev/null +++ b/provisioning/roles/regluit_common/templates/opt.pth.j2 @@ -0,0 +1 @@ +/opt/ diff --git a/provisioning/roles/regluit_common/templates/regluit.pth.j2 b/provisioning/roles/regluit_common/templates/regluit.pth.j2 new file mode 100644 index 00000000..8964ac81 --- /dev/null +++ b/provisioning/roles/regluit_common/templates/regluit.pth.j2 @@ -0,0 +1 @@ +{{ project_path }}/ diff --git a/provisioning/roles/regluit_dev/defaults/main.yml b/provisioning/roles/regluit_dev/defaults/main.yml new file mode 100644 index 00000000..3194c5f1 --- /dev/null +++ b/provisioning/roles/regluit_dev/defaults/main.yml @@ -0,0 +1,5 @@ +django_settings_module: "regluit.settings.me" +project_path: "/opt/regluit" +virtualenv_name: "venv" +django_server_ip: "0.0.0.0" +django_server_port: 8000 diff --git a/provisioning/roles/regluit_dev/tasks/main.yml b/provisioning/roles/regluit_dev/tasks/main.yml new file mode 100644 index 00000000..a702d772 --- /dev/null +++ b/provisioning/roles/regluit_dev/tasks/main.yml @@ -0,0 +1,69 @@ +--- + +- name: Install dev dependencies + become: true + apt: + name: "{{ item }}" + update_cache: true + state: present + with_items: + - 'git' + - 'python-setuptools' + - 'python-lxml' + - 'build-essential' + - 'libssl-dev' + - 'libffi-dev' + - 'libxml2-dev' + - 'libxslt-dev' + - 'mysql-server' + - 'mysql-client' + - 'libmysqlclient-dev' + - 'python-mysqldb' + +- name: Migrate databse + django_manage: + app_path: "{{ project_path }}" + command: "migrate --noinput" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + +- name: Import fixtures + django_manage: + app_path: "{{ project_path }}" + command: "loaddata" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + fixtures: "core/fixtures/initial_data.json core/fixtures/bookloader.json" + +- name: Start Celery Worker + django_manage: + app_path: "{{ project_path }}" + command: "celery worker --detach --loglevel=INFO" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + +- name: Start Celery Beat + django_manage: + app_path: "{{ project_path }}" + command: "celery beat --detach --loglevel=INFO" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + +- name: Copy activation script + template: + src: "activate_venv.sh.j2" + dest: "/home/{{ ansible_user }}/activate_venv.sh" + owner: "{{ ansible_user }}" + mode: "u=rx,g=rx,o=rwx" + +- name: Source activation script in bash profile + blockinfile: + path: "/home/{{ ansible_user }}/.profile" + block: | + if [ -f ~/activate_venv.sh ]; then + source ~/activate_venv.sh + fi + marker: "# {mark} SOURCE REGLUIT ACTIVATION SCRIPT ON LOGIN" + +- debug: + msg: "Successfully provisioned regluit development environment." diff --git a/provisioning/roles/regluit_dev/templates/activate_venv.sh.j2 b/provisioning/roles/regluit_dev/templates/activate_venv.sh.j2 new file mode 100644 index 00000000..75fb3609 --- /dev/null +++ b/provisioning/roles/regluit_dev/templates/activate_venv.sh.j2 @@ -0,0 +1,7 @@ +#!/bin/bash +cd {{ project_path }} +source {{ virtualenv_name }}/bin/activate +echo Local setup of Regluit complete! +echo To start the django development server, run: +echo ./manage.py runserver {{ django_server_ip }}:{{ django_server_port }} +echo Then leave this session running and access the site on your host machine at http://127.0.0.1:{{ django_server_port }} diff --git a/provisioning/roles/regluit_prod/files/celerybeat b/provisioning/roles/regluit_prod/files/celerybeat new file mode 100644 index 00000000..34b9ad6a --- /dev/null +++ b/provisioning/roles/regluit_prod/files/celerybeat @@ -0,0 +1,154 @@ +#!/bin/bash +# ========================================================= +# celerybeat - Starts the Celery periodic task scheduler. +# ========================================================= +# +# :Usage: /etc/init.d/celerybeat {start|stop|force-reload|restart|try-restart|status} +# :Configuration file: /etc/default/celerybeat or /etc/default/celeryd +# +# See http://docs.celeryq.org/en/latest/cookbook/daemonizing.html#init-script-celerybeat +# This file is copied from https://github.com/ask/celery/blob/2.4/contrib/generic-init.d/celerybeat + +### BEGIN INIT INFO +# Provides: celerybeat +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $network $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: celery periodic task scheduler +### END INIT INFO + +# Cannot use set -e/bash -e since the kill -0 command will abort +# abnormally in the absence of a valid process ID. +#set -e + +DEFAULT_PID_FILE="/var/run/celerybeat.pid" +DEFAULT_LOG_FILE="/var/log/celerybeat.log" +DEFAULT_LOG_LEVEL="INFO" +DEFAULT_CELERYBEAT="celerybeat" + +# /etc/init.d/ssh: start and stop the celery task worker daemon. + +if test -f /etc/default/celeryd; then + . /etc/default/celeryd +fi + +if test -f /etc/default/celerybeat; then + . /etc/default/celerybeat +fi + +CELERYBEAT=${CELERYBEAT:-$DEFAULT_CELERYBEAT} +CELERYBEAT_PID_FILE=${CELERYBEAT_PID_FILE:-${CELERYBEAT_PIDFILE:-$DEFAULT_PID_FILE}} +CELERYBEAT_LOG_FILE=${CELERYBEAT_LOG_FILE:-${CELERYBEAT_LOGFILE:-$DEFAULT_LOG_FILE}} +CELERYBEAT_LOG_LEVEL=${CELERYBEAT_LOG_LEVEL:-${CELERYBEAT_LOGLEVEL:-$DEFAULT_LOG_LEVEL}} + +export CELERY_LOADER + +CELERYBEAT_OPTS="$CELERYBEAT_OPTS -f $CELERYBEAT_LOG_FILE -l $CELERYBEAT_LOG_LEVEL" + +if [ -n "$2" ]; then + CELERYBEAT_OPTS="$CELERYBEAT_OPTS $2" +fi + +CELERYBEAT_LOG_DIR=`dirname $CELERYBEAT_LOG_FILE` +CELERYBEAT_PID_DIR=`dirname $CELERYBEAT_PID_FILE` +if [ ! -d "$CELERYBEAT_LOG_DIR" ]; then + mkdir -p $CELERYBEAT_LOG_DIR +fi +if [ ! -d "$CELERYBEAT_PID_DIR" ]; then + mkdir -p $CELERYBEAT_PID_DIR +fi + +# Extra start-stop-daemon options, like user/group. +if [ -n "$CELERYBEAT_USER" ]; then + DAEMON_OPTS="$DAEMON_OPTS --uid $CELERYBEAT_USER" + chown "$CELERYBEAT_USER" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR +fi +if [ -n "$CELERYBEAT_GROUP" ]; then + DAEMON_OPTS="$DAEMON_OPTS --gid $CELERYBEAT_GROUP" + chgrp "$CELERYBEAT_GROUP" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR +fi + +CELERYBEAT_CHDIR=${CELERYBEAT_CHDIR:-$CELERYD_CHDIR} +if [ -n "$CELERYBEAT_CHDIR" ]; then + DAEMON_OPTS="$DAEMON_OPTS --workdir $CELERYBEAT_CHDIR" +fi + + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + +check_dev_null() { + if [ ! -c /dev/null ]; then + echo "/dev/null is not a character device!" + exit 1 + fi +} + +wait_pid () { + pid=$1 + forever=1 + i=0 + while [ $forever -gt 0 ]; do + kill -0 $pid 1>/dev/null 2>&1 + if [ $? -eq 1 ]; then + echo "OK" + forever=0 + else + kill -TERM "$pid" + i=$((i + 1)) + if [ $i -gt 60 ]; then + echo "ERROR" + echo "Timed out while stopping (30s)" + forever=0 + else + sleep 0.5 + fi + fi + done +} + + +stop_beat () { + echo -n "Stopping celerybeat... " + if [ -f "$CELERYBEAT_PID_FILE" ]; then + wait_pid $(cat "$CELERYBEAT_PID_FILE") + else + echo "NOT RUNNING" + fi +} + +start_beat () { + echo "Starting celerybeat..." + if [ -n "$VIRTUALENV" ]; then + source $VIRTUALENV/bin/activate + fi + $CELERYBEAT $CELERYBEAT_OPTS $DAEMON_OPTS --detach \ + --pidfile="$CELERYBEAT_PID_FILE" +} + + + +case "$1" in + start) + check_dev_null + start_beat + ;; + stop) + stop_beat + ;; + reload|force-reload) + echo "Use start+stop" + ;; + restart) + echo "Restarting celery periodic task scheduler" + stop_beat + check_dev_null + start_beat + ;; + + *) + echo "Usage: /etc/init.d/celerybeat {start|stop|restart}" + exit 1 +esac + +exit 0 \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/files/celeryd b/provisioning/roles/regluit_prod/files/celeryd new file mode 100644 index 00000000..12ff8445 --- /dev/null +++ b/provisioning/roles/regluit_prod/files/celeryd @@ -0,0 +1,217 @@ +#!/bin/bash +# ============================================ +# celeryd - Starts the Celery worker daemon. +# ============================================ +# +# :Usage: /etc/init.d/celeryd {start|stop|force-reload|restart|try-restart|status} +# +# :Configuration file: /etc/default/celeryd +# +# To configure celeryd you probably need to tell it where to chdir. +# +# EXAMPLE CONFIGURATION +# ===================== +# +# this is an example configuration for a Python project: +# +# /etc/default/celeryd: +# +# # List of nodes to start +# CELERYD_NODES="worker1 worker2 worker3"k +# # ... can also be a number of workers +# CELERYD_NODES=3 +# +# # Where to chdir at start. +# CELERYD_CHDIR="/opt/Myproject/" +# +# # Extra arguments to celeryd +# CELERYD_OPTS="--time-limit=300" +# +# # Name of the celery config module.# +# CELERY_CONFIG_MODULE="celeryconfig" +# +# EXAMPLE DJANGO CONFIGURATION +# ============================ +# +# # Where the Django project is. +# CELERYD_CHDIR="/opt/Project/" +# +# # Name of the projects settings module. +# export DJANGO_SETTINGS_MODULE="settings" +# +# # Path to celeryd +# CELERYD="/opt/Project/manage.py celeryd" +# +# AVAILABLE OPTIONS +# ================= +# +# * CELERYD_NODES +# +# A space separated list of nodes, or a number describing the number of +# nodes, to start +# +# * CELERYD_OPTS +# Additional arguments to celeryd-multi, see `celeryd-multi --help` +# and `celeryd --help` for help. +# +# * CELERYD_CHDIR +# Path to chdir at start. Default is to stay in the current directory. +# +# * CELERYD_PIDFILE +# Full path to the pidfile. Default is /var/run/celeryd.pid. +# +# * CELERYD_LOGFILE +# Full path to the celeryd logfile. Default is /var/log/celeryd.log +# +# * CELERYD_LOG_LEVEL +# Log level to use for celeryd. Default is INFO. +# +# * CELERYD +# Path to the celeryd program. Default is `celeryd`. +# You can point this to an virtualenv, or even use manage.py for django. +# +# * CELERYD_USER +# User to run celeryd as. Default is current user. +# +# * CELERYD_GROUP +# Group to run celeryd as. Default is current user. + +# VARIABLE EXPANSION +# ================== +# +# The following abbreviations will be expanded +# +# * %n -> node name +# * %h -> host name + + +### BEGIN INIT INFO +# Provides: celeryd +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $network $local_fs $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: celery task worker daemon +### END INIT INFO + +#set -e + +DEFAULT_PID_FILE="/var/run/celeryd@%n.pid" +DEFAULT_LOG_FILE="/var/log/celeryd@%n.log" +DEFAULT_LOG_LEVEL="INFO" +DEFAULT_NODES="celery" +DEFAULT_CELERYD="-m celery.bin.celeryd_detach" + +# /etc/init.d/celeryd: start and stop the celery task worker daemon. + +CELERY_DEFAULTS=${CELERY_DEFAULTS:-"/etc/default/celeryd"} + +test -f "$CELERY_DEFAULTS" && . "$CELERY_DEFAULTS" +if [ -f "/etc/default/celeryd" ]; then + . /etc/default/celeryd +fi + +if [ -f $VIRTUALENV_ACTIVATE ]; then + echo "activating virtualenv $VIRTUALENV_ACTIVATE" + source "$VIRTUALENV_ACTIVATE" +fi + +CELERYD_PID_FILE=${CELERYD_PID_FILE:-${CELERYD_PIDFILE:-$DEFAULT_PID_FILE}} +CELERYD_LOG_FILE=${CELERYD_LOG_FILE:-${CELERYD_LOGFILE:-$DEFAULT_LOG_FILE}} +CELERYD_LOG_LEVEL=${CELERYD_LOG_LEVEL:-${CELERYD_LOGLEVEL:-$DEFAULT_LOG_LEVEL}} +CELERYD_MULTI=${CELERYD_MULTI:-"celeryd-multi"} +CELERYD=${CELERYD:-$DEFAULT_CELERYD} +CELERYD_NODES=${CELERYD_NODES:-$DEFAULT_NODES} + +export CELERY_LOADER + +if [ -n "$2" ]; then + CELERYD_OPTS="$CELERYD_OPTS $2" +fi + +# Extra start-stop-daemon options, like user/group. +if [ -n "$CELERYD_USER" ]; then + DAEMON_OPTS="$DAEMON_OPTS --uid=$CELERYD_USER" +fi +if [ -n "$CELERYD_GROUP" ]; then + DAEMON_OPTS="$DAEMON_OPTS --gid=$CELERYD_GROUP" +fi + +if [ -n "$CELERYD_CHDIR" ]; then + DAEMON_OPTS="$DAEMON_OPTS --workdir=\"$CELERYD_CHDIR\"" +fi + + +check_dev_null() { + if [ ! -c /dev/null ]; then + echo "/dev/null is not a character device!" + exit 1 + fi +} + + +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" + + +stop_workers () { + $CELERYD_MULTI stop $CELERYD_NODES --pidfile="$CELERYD_PID_FILE" +} + + +start_workers () { + $CELERYD_MULTI start $CELERYD_NODES $DAEMON_OPTS \ + --pidfile="$CELERYD_PID_FILE" \ + --logfile="$CELERYD_LOG_FILE" \ + --loglevel="$CELERYD_LOG_LEVEL" \ + --cmd="$CELERYD" \ + $CELERYD_OPTS +} + + +restart_workers () { + $CELERYD_MULTI restart $CELERYD_NODES $DAEMON_OPTS \ + --pidfile="$CELERYD_PID_FILE" \ + --logfile="$CELERYD_LOG_FILE" \ + --loglevel="$CELERYD_LOG_LEVEL" \ + --cmd="$CELERYD" \ + $CELERYD_OPTS +} + + + +case "$1" in + start) + check_dev_null + start_workers + ;; + + stop) + check_dev_null + stop_workers + ;; + + reload|force-reload) + echo "Use restart" + ;; + + status) + celeryctl status + ;; + + restart) + check_dev_null + restart_workers + ;; + + try-restart) + check_dev_null + restart_workers + ;; + + *) + echo "Usage: /etc/init.d/celeryd {start|stop|restart|try-restart|kill}" + exit 1 + ;; +esac + +exit 0 diff --git a/provisioning/roles/regluit_prod/files/certs/STAR_unglue_it.ca-bundle b/provisioning/roles/regluit_prod/files/certs/STAR_unglue_it.ca-bundle new file mode 100644 index 00000000..9258132a --- /dev/null +++ b/provisioning/roles/regluit_prod/files/certs/STAR_unglue_it.ca-bundle @@ -0,0 +1,210 @@ +$ANSIBLE_VAULT;1.1;AES256 +30636262636630653738383536613136363733643931316362326266656433376333386239373962 +6635343138326335313430623566656130663136393531310a343562653666623235336539316561 +31386163663632383436343735376266356134386335363637383536613531323231626535313236 +6163326630306530360a663636393463303062316331623630353235383137333831333239393134 +64353830366463376130633831633835313034643930636166396436373063623039316465613964 +61333538656264353735613034356533353331313735393965363164616331306538383231303932 +31373838363862343931643034643863313738636238376634363430613365356136323237613530 +34323339323337383539363462303863663163373465373262636161346662333738663532316363 +65313464333363643461353539306662353364643663373032346531633362373230653061646436 +34393462326137336163316361363937323738663632386662643338626433626433633235323838 +65653036643961626131383264393138316263366534656663386264376638393639636164323661 +61646166376637396131356339313162343762636234643236316363643063326638366536656534 +31616164313164373336666634356639653831623966333739356462656137363161663635353136 +30653665353334646165663333643863643539373331613263386561353030363862666264353933 +64643439336236386631393934623839626163373463653134656539376262316233626130363663 +65636534303431616631633534643030346534633635393563366266356138383938636264383632 +33616365333863393733646565643236613064616462633661303630613963666236663265636361 +61376336346262346632313833633735356364636239366439393265613866316439643732326330 +38396332363666656636646164646262303162656331636661393738626263383563646261323036 +63363634616362323965616639373961333966303366363937333233356631393938383339613262 +39393461316563383131666539333938313437336462376233353464303739356463323265366665 +64316161333431353264336236373466613230363237316633386661303538666536366462323666 +32373164626330313665653133356563383436663765666437636138343163663533646331346631 +31643638373537653533353036653766663935663636663561343239383666333661343830353133 +34363363333466393761643863393436386231626134663236326335336438633338313963646363 +30623262386437313733353038353231353163326133643139633963303864633739383935363664 +61336265656666643037316139306534323135333763383230633261336139636362396539643539 +34303937656634653862383665356530643064383832363163343331383538623236366535393061 +38373738393064376539343837356335326132363135323935333964383635383965656462383636 +63663661626632396663383838353633663839303936646537363266346661373033663064326435 +62646130376163623363346232346530376638613934623831303636366365313331613436626337 +61346262333933363366653166326330663638643230373364653161333263323035366263623330 +66636532616234636263323366626432363337326564663531323663356166303930653661313030 +32363133313162313331623138356432653630663263623935303739663363323130646133613735 +66333933393266663265333036616465353338656664313230643761303439363035663566393930 +31303633396665316330623962643439313132633531656362333630653537393061316663356566 +39376230643830333035316439346336313464623238373739623636313236316162356337313339 +62376533663138613962306331313066383439373039636631633431316232643266326361666134 +64383437636561323964346134663032663466333831663836393039353562663065643337303330 +62356666353662386439353563643735633730613463666263666539323333613130633765393834 +32343439306636306131386537373164363636386330623534373535323631396464626661323361 +38353935623566373834643661616631373333303735393835643737626234643337653130396365 +65666332323665356330396238633866653761346531303439666236653264323661626135353238 +36643562623266636333623831303439336366646133653332313130336436386537653234666435 +31343863376233623335366333363232653966316230363836613231613130613166643864373565 +35356264383335623539643630323534623265313631383130643739306533663330396434653236 +64376166373639363731663437663331346338373539363637353933386239373738373565353030 +64353261366232643061356165323961383537626239623732393936623461393961353837633733 +34356166393938346232396532353166373534623530646335633338633636336636646630356561 +32363061356632313661386535306339636135623834333231303433343037353633613365326333 +37666235323239383661323536353830383833326565346564663631336465313664346533323337 +38613961313233623033386166336235383362393463393832646538373139333533313266303937 +62346532356632316136633533373665373839623336383435353163386531366466646664326565 +30303639393933373361623333326432366332396137396238336464376131323631343637306531 +37343933373139333333623233386334636436356432303764653235353133366566383031633136 +34616133336663623664616432336265323534373163316338386561623864623861343835633062 +34343738616134366164356337663566326462303933386139643734376332313066613230326363 +66623837323238356366333836386662366435626236333835346662623631373636663033623733 +38316639343638313937353636616638396261333561313032383130393538663366636630376539 +63353566613835343964356635303939343764396631393738646432313765666564316363626431 +65346637656137363266346266616666316361383231343666643063353131386163356638346636 +30383932633264373031373935616230323933373863663564363233313232363066326662303165 +63346532313837396365353365636663313334626433303732326164363330303438636333636163 +35656537623165323666633435386465303063633534656630306664343637336164626433373361 +65376530333361303337623634353434373164626133626263613561613436303161626432626239 +37343536313531626233343530633634613166633735613233393962323165623166366161356336 +35386635366631326266343432386161663033323962313763343163663137643631393166333031 +39346564656665343835616464663231333562616661643234326663633563303964386131656363 +63666363356562383830646633396238623537336439326162376135633665653165326536353037 +37313362666531333837633439643165356534383265643637363933366463343839333961376235 +63333063643634623735363233646334633235373132646139313365303336646264633061643131 +32616465633131356130396465643235353530326564373136313133613064313562306333313965 +38396237653430353533353462373130303262663564653361313465353934353864656235653135 +34613639613633633234386639633230653537393965323363623338656465326531346432333637 +64343436373436356535333865643865373539393036626137626538626635653637666362356162 +30313632396539623962346562646563316264613232343730643565386135346664646363333330 +66656661636235633730393063343634636138383264336535326533356231626530613565336161 +35626232343436616535373230653039303065343432343738616363626635383364373266323333 +33376364666638313564366237356635653731623566626661373961663736666638343061646134 +35313438356531383433636565326365313063383834613837666330396331353738323237363333 +63363963666465313137386537356462663636323737306362326362363266343062626130616230 +64363433343738343632636633373330386464396364383031343531663432363563653032336332 +65366364333133386139636165303964366165326336316534323636633462356335633066643165 +34613030323234383965396233373333393336653237613062323530353762633931343333323865 +30663862373132633834353039653032373737313564333638333762303335636265646162313931 +66393662653933363832623061633634626661356437663331373937396631356131333462656666 +32303166396533643261646130306161326561326533626531663038643565376439633339333432 +64333437366566666366303230616539663564333463666631646163356235636333363633663639 +37666332346161376239656137306430623463653466626663636539666532373565373731613165 +62663532383165656432313762376235333331343738646532373265353066363262333261626137 +31396332383963353066336666366133336138653363613863653833653964663164313831333065 +35333738383232656634356564643634346633313137333863363766643433363631333630643731 +65363161303235323830376638303135613630663362653566363965313436323033643366306630 +39303935636639333961666135633962653362666536663333623430356164376262346662643635 +33323663333832316633373035386334623134326536366236636561373635353366386237323933 +62393435363235396262653065656562383063663236323134313833363833396131643533666235 +37386366343933376338336533316239383430343566626434303537653431626261363438336334 +35363961656332336230386535386531363761303766313563333832633033646461393635376339 +39633630336366373663666239623030326331346361323132363565366366616236346230636632 +38376534363933383965386338313835356135663035326536343532643930383466633538316538 +31353038656533336335376265626139333364633537633662653362393666346163386431326261 +35393261353230373034633666663638306134643066643533323761666264326162343630376661 +65613733343866306364333665353639646263323863663562333965636335613966323564373535 +39363939383031393265613035376635663962386530663639356331393830383130626439346666 +31393532316431393666616535363430636637366134366636643730636431343034336539616135 +38633063333063383766386265336363386362383136653536616663376463333935356162343930 +36383831666537313936393033363738666335653739646431363039373939626538343037633631 +39383439373336336561663431626265666434646565356438336530643863656464323034353565 +36366563323836336162373465313938646239373637613066333238323533346338353834636631 +30333262376638336537623466643736653562336336663436333963366464666131303862313335 +61353862656435653939343362393934303633303333366231646431656234656638613033383133 +31353262353231663633633063663537353536383138366132646364353661363135336333323133 +64613231626662666364313232333633386265353935363065333933666165633862393965326637 +63623962616164626237303466623565623032666431383633323233633861326132346263386631 +64386364653633363965356664636434393031383663393137343733343732363239633436663636 +64346237653966363538303632363461663030396237623661356438653562396232313935626164 +64326162363264323831663965383639393937613931663239316663323164306537326363376339 +33333063373464363065336132613230643831303937373163386263646562313361306133306639 +36636264373638326663613236353439383532323032393431373333626330313235623362643137 +30636462643536363638613936383931363663343964363038373834343164633062343265666137 +30373734396232343936326330623362316636616535643136313765356439323934386364643631 +34316630366332366432373739363637623437363132646330326361363366313633343634383132 +34626633343163613136343665373931363065306232313336356461373366623934306563383935 +35373930633334343864306165653034386133393636386662303737303136613432333531313461 +62323065343037386231656335326364363761396532346661343664636637633334383131613833 +34306465643133383239306534383035303363353766613631643464383264656536323866326464 +38666665613166653638633039666261326135363833393832373564333765353134636138343266 +64373536313666353332613535633061363835363839323430333430643863343461643236333937 +62346262396331613536343539653766323561343639643766653535353335383736333464613331 +61336337613737356236636333393236653263663065353431633537666161373638663861363863 +36393364616566343561393364313531356134626431646261346363343939616332313631636331 +31393435373265313836653533323237613336333061306330636665626233613537383932316235 +35646633653664313834376466306335653465613866393939323265316436333062646662656462 +36313861306533326163306266353538396436386365393464613335646432366461326331623664 +35616665666337663163663631393539663731376333393339373065643363326535643563383532 +63656466623939376632636433316661613730386363363930613830386638653837323938373030 +34653565386564333866336337316164663931396630333634336130383465643061633239656638 +66666166303835326365353433636130653038643938653365333431646561306536623037666231 +30333830376637653932613961353931363537336462643030376537386539623636303038363862 +34373036393931303465626563623664663532666166336334653234346561303538313036343565 +61363734333737393131643661326331383036333363653333373536373134306436646139636561 +61386462323832653061313034616532643265343636313366346537356164346461313436373637 +34316663356135636231613330323431316566323361363636633436653864633564366366383339 +61633266343336643430623138326436383361636161326264346365643536343838333138646563 +65383230373361663461383236313832366334303632313935313263646266393030313238613334 +66626631323033383334636561313666653165356135366435613438323662353135633234346662 +33333336646166643862396361383636306431353439333562633533303265303266613662306162 +34383062333166393739656365303738373361373436343064323636336634353232383232356334 +35633561383735316663383333303334633631346339323562353634396533343636653963653462 +61393039303366626563393737306336376437666138393562373933333335633435396632333232 +39666435383832663462626563646162666565393530393164373963386161666436343263316639 +30343064663133616135613164653937366636353062303139366261313165373362643365316663 +33653630633732623466343236646136663730663938333234613163663835393036363161386332 +62383833396164313132633535323530633937626437383462663866346163623234663564306533 +65326362636433333930623663653031313438363930373462663639366434633665656138303866 +35626333336532346663366530303061343835376239643466326361613030613730326130633165 +39333465393466336231333335616662386238346537633164666636333133306266613064343165 +39653963346133333234353266323065656237303233623264376233616334623665323433623632 +63316262306337386535653233336635616438356565343433393662653036663736663663666435 +33333433343566623331333961613662306236386439386135653138333638366566313534383934 +62626261303530306237653637363933393634663330336462393932353230313730336362376134 +35343530363431323366613361643636663961366238636537616237633965666639633265376437 +63363930353064346664323435313136316132373237356332383537623032633831353563326230 +65626166336166363164613130393165356139353439353436666537346362326635386136313464 +34383633336636376137643733313637373535643966376435353339363535653139313739313362 +65343434343364666639306663663665356533323635316534316561313263663662623764326138 +38386434316535653262616530643164663335323436386365313361656430616535346463643765 +64613231623333363835386337643334333039363835343731316165346438363234666134343263 +63663036663566373734656661613432623761393964313166393532396664326230363230303161 +36373364663137373234383134363966633935666365303430343539663461623561383236626137 +66623964333766323534316439643666323666336539393566316331363862666561656634326166 +64383236633638663163666236633531346330643066353566336337646265623361326261373862 +32626538316631303465396436643236376161613232666339373537383438633630316365363065 +31653433326333613431303936333137323632383163323561313636396331376664656365326536 +39323632623861333466333530643864616166623261346237356431326335343431373164633366 +34363932656234613431306135323434353164323461346262656337336137616430386533313933 +65306566373634363933616233316562643930666161643234323864336631343032326462623365 +65363036633061643463343637313933396436636333663861393333353732383736633534303864 +62376339343938383639626237373961623931616264353264353337333133396564623831643338 +39653962623766643239393061643938643066386564613932656565306564303066316165336230 +62363330653137616666343333323636663462643264656364396138626265623964663730636561 +31356339323934366637623165623039323439333434653336623962643734653436376462386232 +64393863353164373734313262383638393961623466653034626666353361393230623933373336 +35323661333330393835363064396564613766626665623866346334643463663865323264386661 +33663561616131616134333564343334343765373061393131376231653536353163643435613564 +32376466363230363930393734663433313133646238396366356361663636343362313237303766 +63613538383836646333366664313637333537303333373537646130393631656636623461383533 +31333661376236323736666136393062643566313131383165663965656637303634366330666539 +61336265356662336236626432643738343038396263393665396337633837303761613332623436 +33313235323938333333666437613731376562376233353664313362356433383938376436373863 +32633131386462333838323536333439323733393266376632386530366363633337323963353437 +37653334626434616433643930363765366439613236373731343339613237633962356531303433 +38333261613062323963366131633738613463363364653531663639626234383263633963336635 +65343330636330353363356134363138333031393838623635343335393462343036316638623861 +30323638373032653331616361383338333761386264623435656561623337303863323536633932 +61613964363538313435363231613834323333336364353962346265646233613935313632343738 +65303732376561643763336162333962353136663136613466666631323063646432323130616266 +65663431626562646537366661393638346538336538666466343261396431383232356238353062 +37653031653766333931393763346366356563393261363438363535303163303962306630306665 +62346633356463653465363965396164323437346132396138316562316237303033396233636336 +30623039326132393534633937623363656666663366643130633161646566386135303939383762 +33356334636565643761323638346162373636323433306436303331336432333830623739643237 +64646432366466326139306663356438613433366534616462383938646239643262373836363032 +61623735666238626435316530363833366135633563663530643631623539333832343561323138 +32383138303464393265373665333736303861646464373861613730653861353463323837383737 +30356437653833376631303636393739636663663936656663393130616637303332393636363431 +38663837393231326536643033376663316138363234306637613135396365616636656236646335 +33633962626135343564633337663936393031316133646334303635653130626131646531396134 +38343631613562393435326139366330373064393839636138323466646533303538 diff --git a/provisioning/roles/regluit_prod/files/certs/STAR_unglue_it.crt b/provisioning/roles/regluit_prod/files/certs/STAR_unglue_it.crt new file mode 100644 index 00000000..3dd020d3 --- /dev/null +++ b/provisioning/roles/regluit_prod/files/certs/STAR_unglue_it.crt @@ -0,0 +1,100 @@ +$ANSIBLE_VAULT;1.1;AES256 +66366138323934613133623237633539616236326462373461303832393739313466373236323765 +3461353265343631356335643139363335356262346238360a383136303237393662303762393766 +61346362386338663037396631633932373834303265383662356539323766393466656564633465 +3835623862356266390a646463633764653431353537643265363764653934656430646363373335 +32343135303266623365656532633061373564623664616564343638636138623433363964303366 +63323939396365363539366562626135626662336236313963613233633637313731313465363636 +39386237393034383263346164623036646535623463306330663034383632373836333661666435 +61656662353762653266363036373430343333653835646365613835303935396230363032636164 +64613730663339316261313664633636613763313631653839313465336562633663306563633561 +38613661333766366633333463376162306365323330356339613266326331353866316638363237 +33646165313865313431666163613234366133616263396630303362333336323638373131396334 +39656534616331643530646530316335633730323166373830353262366465306631636339316266 +32303162313438373531616439356563303030383136613531353561316234353632646232396433 +38643463333836326435303733373239626562363264653532323334356262346133633361373963 +64396564313630393164323231313937643435613234376436386563623435633666616331643530 +39366536616165303562663638313739353763656134316132616162303161623130616263306366 +65613264623935333134383733353637653336636532383165646338303633353330623231383239 +39343834643038656539623162353561646364393162323839643533333363616437393239313034 +61356134643031356536653262663833336361653632626364336565616163376238326334663661 +35623338393730636237616161383032353762383965633962343330353235643363346633313462 +36653365346263323062653239373132323734626363623337393635373738663931656363383136 +62613836356562363866623436393131323130306636356235343035333534326331343337383431 +38613565383365666632326238363165313631373262336234666434313065363363346636653339 +36363432306639303266366665643934346562663934666665343030396233666534633438396332 +31323662363130616338333233373961316639633436313737353530646135373533613433353034 +62346432623261346334623738663835666639616564373961643439336432316365666665393135 +38623936616361313634333339353133633165663936616332323938396533393235636435376439 +62633537633136386366313934373263383730633334343636373035316638343334356530613530 +63396438343139383439666539383531386437313865303864316437363563663065643266353138 +66323133646463653066323466653662653736306162636565326663386362366332303761653564 +31383133396131663563343339623563363239363763643530383833353263646264363565656535 +64343737663261653530623836356430666462633964353832663964396462363430623336646336 +65356566653938376132663230333033376261376538306266643565613561373636383532616139 +30396564613564333964303262656162313839663435666539393734376639653562643735393037 +34613864353764303661653561383466663730333932663139616164333239633961326632346230 +30316138626562346434643033303333333234396533626633333437316636323062643035623664 +38626434366261326663393839343765363133623339373738313563653736373565336164356435 +37623837343437623833623137373662653934363133633366636436663831653737376631376431 +34363461323535323337343632653430333961343165633864346132343938313361373864363565 +32663734626631323930613638323133396135313562643536343038366233373136653330626239 +65313933636136303365353466646533353236343934356330356161343433643139383764393134 +32356331653831633832376262356238336634353362373837646563653835613634356463653466 +30383361356631616538333565646435656361313839346165376231643633643634313863663137 +61333236313436383464663439366637643663356535613861343831663737623364303339643733 +36373461323130333639613235373961313736303436666361613134323265386165616237393164 +34366530363034376437393866333861646636396434636631343033633565396164663833623331 +32666161636163333266393361383838653333326437303235326565306663356366613430303237 +65343937653439353334343834303234643136656565366461393838653739336233613234616437 +62643065356462306565363964663332663564313734336239633833306135613662633535666662 +36616639323332353864383733393561666464313466393535373961613831313463306461663266 +37653230663732393061616365656638623830346536373932636461663532343532366566343436 +63376365643061623839393139333661643439376363396564363237346461393264663131616162 +32396464363231613231363561373334646362636536343732396364653132663664366434313538 +39396262333232383934396335653461346338316564303563626363646136633266393937343434 +34396234363362336232653136666639613466663833303062356264633461643932613162303031 +33663539366332643538353632336433393564366565323034393531626236353432623531383033 +64613435623761623562363563323364396166353265363039663932626431666339376632353539 +63656330626438653366396635353236663762666439613237623638663731306331313564333239 +37363663366134303037376433323735366266613831356635663932626162343639306366386439 +61643831336139303133336366366165303934646362303665643135386462353565303932383930 +33393334353235306534366339613066633434393038636331366265336163306334323638393264 +64313538316632373430656532623532313063613337626165353365303832373566316131666336 +62353062343565633836306235343134323433303633346130363362633263343564616535396263 +65666666646231336636616364646565303538343361653932356135393161316335343333653439 +61373266633033653931623631643430613137393633393063353833306463663630333434616462 +33653230613639616531666335336131373636323065616239313733323664623138313964303930 +35366665626362303161396562306639613435396331366363616138613735383030366362396337 +66356666643131393433343237346533383335376462383566643035616438396366633737393133 +66323630656539363237646663363764363536373266383036636166333834366663613863663533 +62393235666666653433613665376431306439616138633533656362323436613231303264303764 +30336665336661393866343935313465626264303139353632356137663439373232326339393136 +64306365353639626565653965666133346364613538333135653831663032613135653263353965 +63373532323062653630646363323063383065646562313539373637623463313333313535323866 +32363631613035653637663935313535626333333433623735663439383239373231613037303736 +39633436383361356633373037333362363861346263313038373131653938663930666538306432 +34386163316163623064376132653062333535396631393363393265303964356431663439636234 +64636138333031656364656565346163663533353333353666373466373734633263626439316230 +65313031396564613163333364376637303539343563613133613133376239623066303139393866 +32623135396134396439653061386561666433613536336566613530656530333433343537623866 +31333364636631336264636531343365633264633433643661353164653831343836323763343033 +37386131306563626437343034333330623932303639646631613239303331646364323465616562 +62353030633765393237653161636165363465336136333264373832616537356531313066643263 +38346331383061373133353132646562313630643335376565396662653830656538356165356137 +31396232326666613236313961636334383962373533613566333930313866373334613064376561 +65313565303630326531613131316463386636623830346131656532363632613032303466623334 +33353633663730306638623566326533363065663363373537353130393938313936383763663966 +34336535663565633162313732376237336463343833303939353965653665356563326534643033 +34343638666463363462363235343731346461336235306264643866366235663961363461373930 +63326334323363656263616531373861633936636339623835323936373661373364336233316631 +66366462643663316162383438376162663065633333353138363836353331343162396636623130 +62383461626534386664633166323764303631373731366133633930643232303934666535393237 +35373462313561353561643866623761313839316662373134363431373562373062313430613462 +37333635313037656433656363313864653037313732656232323639383838326263323564643263 +38373337353635353836366136326334343661393064316139373431313330653966323763306337 +62333066323961623535336232303234636138306630313732373364613363663434633734346231 +64663930633162313937343130343961356437353366306338663636366631326366663938363531 +63353863306137653237656330656237356563346337343262363664313339323863616438373537 +63643235306137363264383238316434313331336337356364366261313835656562643566666130 +633536646634326262663866316566376638 diff --git a/provisioning/roles/regluit_prod/files/certs/server.key b/provisioning/roles/regluit_prod/files/certs/server.key new file mode 100644 index 00000000..2e3e98f8 --- /dev/null +++ b/provisioning/roles/regluit_prod/files/certs/server.key @@ -0,0 +1,89 @@ +$ANSIBLE_VAULT;1.1;AES256 +32373237336239343336393066383464393861636235623430343533636365306430323738643234 +3538336532623734333038333832393735343363363566340a643638636634653735656635336338 +39396461646661353061373636313032333065373562373036336232346133313334333862353034 +6337653431323235650a663536386561366531623363303963353539326339393034313961393362 +30306235623461326365646365373835333235303965336635363361366336303236333237383539 +61383438316464336338633163366532323435616563343463623266346632393930353332626137 +34396538653134373433333461373337333639393530383738373764353731363264373835626364 +35393163333462343562303136313264653764333038343838656562653133353934336666643534 +63366264393462643065323865303033636133663164366334313564333262633736626263363338 +39376164343330666332333534313634633137653432343232656464363066356336623166303030 +34653432366563663432343164636665373139346435396135303736653030653930393963663538 +36333636623832633630386235623365363065343936363031613165383534353837353231373164 +37373038363361633330653633396562323738663739316634666137306161313233633561383064 +30323236643635663766393862343363653866303431346535626565356162353433623132363031 +62656332383835386136656534636135346234326561623037396239303034353961396134396334 +35303463366439363336363666623064623564323032646337366332666536373064353962373461 +63306166616535356231396566316433633062376164303434323639376339643731393461393536 +65633363616235343532386435323736313138666661666434643935623266323133336463326532 +33326364346364626165666262396133343736656335353732666362613234343163343465326361 +33383136636364383466363666316131383366623665323561636130343337613539383134646535 +31383131623237636433313133336162633537653533383435336461616439343035336164333363 +31623638333465306538313637636436626132656534313064383663393230653132333938343537 +65343339333037613332316534336133373864666130303166393038373531396266303832383632 +65343531616661303363303966303230353630356437336164383038366563363166363763396464 +37386330653563613063323438363737313565363130353264613236346565323837326631363935 +31346365653938653566646437623333326533646235343966383031656132396539616661393461 +65333235306432666539623964393132616436653430383236353033333366336363323539333636 +64616563376464646534343838616437306232393262313065353936356235373231613561323866 +61383536636361363039656138306131383732326464613931363837376234326433376533643861 +32616434383536373532383238663263643862373738333338343332303735663863346331663037 +35643637356531323639623533313865656132353139323436363661643263323633363161653235 +37636635623865303536353264313263373938366165623364643337313831653161623231343764 +33386162623531396234623937633465653930636637623837653138373365346132323731346130 +64613338386662653833653034313066636566333839306539666161333333616261653537313363 +64656632333462633232396236373666366464623464653434383832333365376532626531313735 +30313335353664643566313437393834393262333665666366326463663761626135326434363931 +36306439376138313838613532343663383938366333316432303930326239646232623633373564 +62316632383131626432333461323330366165366331303735333330363335366265316330663563 +64393231393136626162386335626433336337373765623933346237643532366662616434366163 +37373832303664303836373434343032313731323362353031346438643335323131366538653334 +33643432646339383865386238666134383861616437663238366365663737623663323137613865 +63633965323933366332363131313834653564636336303966656663366361353731316336633233 +32623339343838373639343534326365346135393137303736346634303863333664376332636634 +30303938353536636365353338393932353435383635326435666133353430323464333531356563 +31353733323331656538373932643332316332386437373938373635633832383662316537346132 +35316339343538343462363237666332376461363262623438623738623732383337373738346235 +64333335396336333337643235616436373736623339366236313938653433343661366332646265 +34636530666636363764366533643739653561626134393936616632616264663230616164376132 +30656336633230323535653766636361626562306262326265626166343036643034303730306164 +63356131333739333338353835363430363864333063363238303861323033643534366264623433 +30653639633862376232393065626636396137343635343030316630313863323365363764616630 +38346336663932626430613437656437313462633039393934653532386535323836366465383761 +39323732666339386565653836323461623238316564323333363461396161643338633137646335 +66373461633233333337663332323064373662636535376433613232653137353834373630663366 +61343066303366666362353837343337386631653461646230656533663965626135383131346635 +31623131653264353861353630646662303835643738323565383233336334356264353939373933 +31303964346563636437633532383762383234303130366331313864386330653130653437356466 +38373135333066336139336332643666373932666565303062636465326236623963323337633634 +66646633366532646232326435663065393035386438343030323038663033356639356264663532 +61396130643135666266366664323234353065303031343531366532633532363534646536646235 +62383531393832643137633332353364333230383361663264623564366539323132623639623939 +61323263373866343933653734323661383634636139383833323837303236326364666466386336 +34316465346261366131316535303563623238346530643264326539653432633237656133613532 +30663738313139333461346163626130343535306538623763343134623832346132656666393761 +35316164646635613032326565353163656134616366386364306436303134386339346462653262 +61383961656334653564623262366265316364366538353362313233343239396265383235303534 +33666366323466303534333165653334343437316435613566326338666336326664616133313062 +66333339346335626663323335373939303163623331303133643937653362666430323930623462 +30393239633763666463643066393161353235386461633066306235376261346139363330663235 +31643539616335396331656364383265346333323661333066353732653336616330303931376164 +37643931313337646337333236323939613333303834356662373836633631393736616462363338 +31623064303936306330343361313763336239316362633732326564653566313265616566336135 +61616538653365313666613366313064623232653563383465386535636530643831633735323433 +30353239333166343366643738363834613230316463636339666434633961386335623238353030 +34356536376164613338376534353438383039383930316439653732643339653531316530393534 +35326165666439396537396464656339333366333535366530353064396436663966333465616630 +33666233313537363165333738393362656631386564376365616266393137633931643833343232 +62393663663836303563386235383363623966316635366133353165346635373063383666373833 +35633264666139616463333339653733376431363761653433653138356364383865633937363433 +33313361653536633066656164616331343033373339336334666635353630636532323632323261 +39303937626633613434653835376538356164396631326163346465663337386230656139396237 +36613762346462626135323233393537616539646234663866353433396530383966613333376137 +37373461333561313966303239633834663837656230613830303433353639643431323930633238 +63383161313938663737396539663163303161633732393130363737303732313166623534303339 +65323162386430393639303435653436656239303032663761626462633565626161656632626162 +62386631316434383239303631343536363034626663626430633635353933313533316337613532 +33383335326637626535336664626663376332316236633735663339373131373630643665356133 +31393664663737326638 diff --git a/provisioning/roles/regluit_prod/files/certs/unglue.it.wildcard.csr b/provisioning/roles/regluit_prod/files/certs/unglue.it.wildcard.csr new file mode 100644 index 00000000..7328e869 --- /dev/null +++ b/provisioning/roles/regluit_prod/files/certs/unglue.it.wildcard.csr @@ -0,0 +1,58 @@ +$ANSIBLE_VAULT;1.1;AES256 +65656166313438643163366632316530386139623538636439633638636566383566646239306131 +3938333565313734613639376539323233353932373635640a313831613637383734636539666463 +64306331656564626233383831633862623861346364366632313733623263306464636264363965 +3933326435396164390a646439366537323232633232373339343538616431343137373338326166 +65373365613465616631623463313364396332366539386462333737623737343330393662646533 +62353663306531663935623765353838333138346630313333373066303835323461383630306662 +34316363316661613865616163393133626139663162393336356665373465353766656661633731 +37373563396437366661373134623664393430616532353530303861336238666539306562343662 +32613431393331306234643362323961343261376238353635366132623638663463343730343730 +37323733313739636238376538323264333238643532306439366463626233613237313933383333 +31373064343036616239616562373264653163396265613935656638613662663364633866393638 +62303563363763356433376634626234663234323636366232616431646534383730346233333963 +31616263353462653932343537343863326337643037326265666433623965646264303066316139 +31653864383331626231313736623563316330393563376562303933313237383939396438623231 +65383666336565393236326433646561346635356661356136306165323432383531646264323064 +31353738663861306135636131333261333964663338636637306665333663313164393537396663 +36666663616634323137333835626133383737666632316336313661656434376239616437346636 +62643035376637373031636330646638356562643962313336653964616337643064346562366531 +33613935656630633736386632616162663535366466663637313339323939646136636165656166 +38346562346331323738393934396362316361643538653163333935656139356535363432313532 +38633336646332386661643464666263646432373134306639306561663134373164326632613531 +64313162303263333534666436333634663262623632366631633865336433303564363138353566 +36303862656531343765643965666531613231343035636537373030613932303039623131363830 +37346263666637373639643930303438316430663462333430613335613131396566303533343864 +62373439663236636232353230343433336137613930623133303936323562313061336637306566 +34383336646336663263373334323131316262613136353239616630303264633238383266323464 +37623864646331363735306132393936306162393463313736366166656439343039626434353739 +37613532393830323431393964333437306366313335393434323463346133343237303732343962 +33373164363135363335323435636666386231363463373864663933373430656239366539643164 +30323038323739373965616630336166356362653833303132336230323661373737666232346630 +38393933303736306537383364356162656339613461333262656137636662303532663737636237 +36333661663734643363636661353337616162396666356663393432633361313534333537393161 +66666165363635346162623965333061386563663166643736653134303638613332313637333064 +65333438333661343664303361316631643763323164386330636139353932646635393963656336 +36343362323332336130633533663234343236393639323062663962633336626435653137306539 +63633866616438623764616631663533363233346362336132303861653039386133323965643863 +30633932646132633862666266323761656438343935636332326263653437333366306338636137 +65303538613661373538313437646466393536313665623666396235353962306634386261396337 +61376439636531383631383234313230303731653435393964393835393236653739316634623363 +61363730333632323039326438366633336462656135366164663434383561356337393636353661 +64616435386238316265386565633938623935663332633062316163356337303765366262313534 +61396361326333616136366435666662346637663864326561653634313030303033303132366132 +64353635383932633733303333636137323237393764396136313661353463306137316563303232 +32363063626630343230333065376638626236653532383766363161313862616336396334303764 +38393262613531343134653130313237343036383464393739353631636235343930653537373935 +63306431643132643362656433313061303838306164643236316166303331313636376431326239 +66386635333631653232383664343864383739663364363131373062623835363635393930326639 +33303733353761336638363935316232336533366339396166383539363963373536346232663865 +39613463386138363364316365373161313130316638616635313235363235396166323935353664 +39646163306161323536366532333231373530636234643764366134306164333431336636333533 +32333966393634393135333031356533666531613262313432346366373262373565323962323939 +36343764303866653638336134653263616561396332643030356434383531343166356466646633 +37336564613131633534313064303933633134393131656536383439393633366164376636353634 +34663236663163633338303838303733643262363834633064313532626631646239306564313361 +62616331306330636366306633366430353964376466313032356434346532366362356136376536 +33613962316539376138323033623736366531643261386535653733303465333331383131666530 +38336561353633303639616635656566323130616561656235393135616631356334 diff --git a/provisioning/roles/regluit_prod/handlers/main.yml b/provisioning/roles/regluit_prod/handlers/main.yml new file mode 100644 index 00000000..0c679221 --- /dev/null +++ b/provisioning/roles/regluit_prod/handlers/main.yml @@ -0,0 +1,6 @@ +--- +- name: restart apache + become: yes + service: + name: apache2 + state: restarted \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/tasks/apache.yml b/provisioning/roles/regluit_prod/tasks/apache.yml new file mode 100644 index 00000000..3063add3 --- /dev/null +++ b/provisioning/roles/regluit_prod/tasks/apache.yml @@ -0,0 +1,79 @@ +--- +- name: Install apache + become: yes + apt: + name: "{{ item }}" + state: present + with_items: + - 'apache2' + - 'libapache2-mod-wsgi' + +- name: Ensure apache is running and enabled + become: yes + service: + name: apache2 + state: started + enabled: yes + +- name: Create apache config + become: yes + template: + src: apache.conf.j2 + dest: "/etc/apache2/sites-available/prod.conf" + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: 0664 + notify: + - restart apache + +- name: Create static directory + become: yes + file: + path: "/var/www/static" + state: directory + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: 0755 + +- name: Create WSGI Script + template: + src: prod.wsgi.j2 + dest: "{{ project_path }}/deploy/prod.wsgi" + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: 0664 + +- name: Remove apache2 logrotate file + become: yes + file: + path: /etc/logrotate.d/apache2 + state: absent + notify: + - restart apache + +- name: Disable default site + become: yes + command: a2dissite 000-default + notify: + - restart apache + +- name: Enable prod site + become: yes + command: a2ensite prod + notify: + - restart apache + +- name: Enable SSL rewrite headers + become: yes + command: a2enmod ssl rewrite headers + notify: + - restart apache + +- name: Generate static files + django_manage: + app_path: "{{ project_path }}" + command: "collectstatic" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + notify: + - restart apache \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/tasks/celery.yml b/provisioning/roles/regluit_prod/tasks/celery.yml new file mode 100644 index 00000000..9d6d1d59 --- /dev/null +++ b/provisioning/roles/regluit_prod/tasks/celery.yml @@ -0,0 +1,67 @@ +--- +- name: Create celery user + become: yes + user: + create_home: no + name: "celery" + tags: + - celery + +- name: Add current user to celery and www-data groups + become: yes + user: + name: "{{ user_name }}" + groups: + - celery + - www-data + append: yes + tags: + - celery + +- name: Create directories for celery + become: yes + file: + path: "{{ item }}" + state: directory + owner: celery + group: celery + mode: 0775 + with_items: + - '/var/log/celery' + - '/var/run/celery' + tags: + - celery + +- name: Copy celery init.d scripts + become: yes + copy: + src: "{{ item }}" + dest: "/etc/init.d/{{ item }}" + mode: 0755 + with_items: + - 'celeryd' + - 'celerybeat' + tags: + - celery + +- name: Copy celery config files + become: yes + template: + src: "celery/{{ item }}.j2" + dest: "/etc/default/{{ item }}" + mode: 0644 + with_items: + - 'celeryd' + - 'celerybeat' + tags: + - celery + +- name: Start celeryd + django_manage: + app_path: "{{ project_path }}" + command: "celeryd_multi restart w1" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + +- name: Start celerybeat + command: /etc/init.d/celerybeat start \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/tasks/certs.yml b/provisioning/roles/regluit_prod/tasks/certs.yml new file mode 100644 index 00000000..0804aceb --- /dev/null +++ b/provisioning/roles/regluit_prod/tasks/certs.yml @@ -0,0 +1,39 @@ +--- +- name: Copy server key + become: yes + copy: + src: certs/server.key + dest: /etc/ssl/private/server.key + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: 0600 + notify: + - restart apache + tags: + - certs + +- name: Copy STAR_unglue_it.crt + become: yes + copy: + src: certs/STAR_unglue_it.crt + dest: /etc/ssl/certs/server.crt + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: 0644 + notify: + - restart apache + tags: + - certs + +- name: Copy STAR_unglue_it.ca-bundle + become: yes + copy: + src: certs/STAR_unglue_it.ca-bundle + dest: /etc/ssl/certs/STAR_unglue_it.ca-bundle + owner: "{{ user_name }}" + group: "{{ user_name }}" + mode: 0600 + notify: + - restart apache + tags: + - certs \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/tasks/main.yml b/provisioning/roles/regluit_prod/tasks/main.yml new file mode 100644 index 00000000..1a8bf265 --- /dev/null +++ b/provisioning/roles/regluit_prod/tasks/main.yml @@ -0,0 +1,120 @@ +--- +- name: Install prod dependencies + become: true + apt: + name: "{{ item }}" + update_cache: true + state: present + with_items: + - 'git' + - 'python-setuptools' + - 'python-lxml' + - 'python-dev' + - 'python-virtualenv' + - 'build-essential' + - 'libssl-dev' + - 'libffi-dev' + - 'libxml2-dev' + - 'libxslt-dev' + - 'mysql-client' + - 'libmysqlclient-dev' + - 'python-mysqldb' + - 'postfix' + - 'libjpeg-dev' + +- name: Create project directory + become: true + file: + path: "{{ project_path }}" + state: directory + owner: "{{ user_name }}" + mode: 0755 + +- name: Checkout regluit repo + git: + accept_hostkey: yes + force: yes + repo: "https://github.com/EbookFoundation/regluit.git" + dest: "{{ project_path }}" + version: "{{ repo_version }}" + +- name: Install python packages to virtualenv + pip: + requirements: "{{ project_path }}/requirements_versioned.pip" + state: present + virtualenv: "{{ project_path }}/venv" + +- name: Add project to PYTHONPATH of virtualenv + template: + src: "{{ item }}.j2" + dest: "{{ project_path }}/venv/lib/python2.7/site-packages/{{ item }}" + with_items: + - 'regluit.pth' + - 'opt.pth' + +- name: Create keys directory + file: + path: "{{ project_path}}/settings/keys" + state: directory + owner: "{{ user_name }}" + mode: 0755 + +- name: Copy keys files + copy: + src: "{{ project_path }}/settings/dummy/__init__.py" + dest: "{{ project_path }}/settings/keys/__init__.py" + remote_src: yes + +- name: Copy django settings template + template: + src: prod.py.j2 + dest: "{{ project_path }}/settings/prod.py" + +- name: Copy key templates to keys directory + template: + src: "{{ item }}.j2" + dest: "{{ project_path }}/settings/keys/{{ item }}" + with_items: + - 'common.py' + - 'host.py' + +- name: Create django log directory + become: yes + file: + path: "/var/log/regluit" + state: directory + owner: "{{ user_name }}" + group: "www-data" + mode: 2775 + +- name: Open ports on firewall + become: yes + ufw: + rule: allow + port: "{{ item }}" + proto: tcp + with_items: + - 22 + - 80 + - 443 + +- name: Run redis tasks + import_tasks: redis.yml + +- name: Run mysql tasks + import_tasks: mysql.yml + +- name: Run cert tasks + import_tasks: certs.yml + +- name: Run apache tasks + import_tasks: apache.yml + +- name: Run celery tasks + import_tasks: celery.yml + + + + + + diff --git a/provisioning/roles/regluit_prod/tasks/mysql.yml b/provisioning/roles/regluit_prod/tasks/mysql.yml new file mode 100644 index 00000000..14733069 --- /dev/null +++ b/provisioning/roles/regluit_prod/tasks/mysql.yml @@ -0,0 +1,48 @@ +--- +- name: Install mysql-server + become: yes + apt: + name: "{{ item }}" + state: present + with_items: + - 'mysql-server' + +# - name: Ensure mysql-server is started and enabled +# become: yes +# service: +# name: mysql-server +# state: started +# enabled: yes + +- name: Create MySQL database + become: yes + mysql_db: + name: "{{ mysql_db_name }}" + state: present + +- name: Create MySQL user + become: yes + mysql_user: + name: "{{ mysql_db_user }}" + password: "{{ mysql_db_pass }}" + priv: '*.*:ALL' + state: present + +- name: Migrate databse + django_manage: + app_path: "{{ project_path }}" + command: "migrate --noinput" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + notify: + - restart apache + +- name: Import fixtures + django_manage: + app_path: "{{ project_path }}" + command: "loaddata" + virtualenv: "{{ project_path }}/venv" + settings: "{{ django_settings_module }}" + fixtures: "core/fixtures/initial_data.json core/fixtures/bookloader.json" + notify: + - restart apache \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/tasks/redis.yml b/provisioning/roles/regluit_prod/tasks/redis.yml new file mode 100644 index 00000000..ca646847 --- /dev/null +++ b/provisioning/roles/regluit_prod/tasks/redis.yml @@ -0,0 +1,13 @@ +--- +- name: Install Redis server + become: yes + apt: + name: "redis-server" + state: present + +- name: Ensure Redis is started + become: yes + service: + name: "redis-server" + state: started + enabled: yes diff --git a/provisioning/roles/regluit_prod/templates/apache.conf.j2 b/provisioning/roles/regluit_prod/templates/apache.conf.j2 new file mode 100644 index 00000000..874f8dba --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/apache.conf.j2 @@ -0,0 +1,71 @@ +WSGIPythonHome {{ wsgi_home }} +WSGIPythonPath {{ wsgi_python_path }} +WSGISocketPrefix {{ project_path }} + + + + +ServerName {{ server_name }} + +ServerAdmin info@ebookfoundation.org + +Redirect permanent / https://{{ server_name }} + + + + + + +ServerName {{ server_name }}:443 + +ServerAdmin info@ebookfoundation.org + +SSLEngine on +SSLProtocol All -SSLv2 -SSLv3 + +SSLCertificateFile /etc/ssl/certs/server.crt +SSLCertificateKeyFile /etc/ssl/private/server.key +SSLCertificateChainFile /etc/ssl/certs/STAR_unglue_it.ca-bundle + +#SSLCertificateChainFile /etc/ssl/certs/gd_bundle.crt + +WSGIDaemonProcess regluit processes=4 threads=4 python-eggs=/tmp/regluit-python-eggs +WSGIScriptAlias / /opt/regluit/deploy/prod.wsgi + +# generated using https://mozilla.github.io/server-side-tls/ssl-config-generator/ +# intermediate mode +# 2015.03.04 (with Apache v 2.2.22 and OpenSSL 1.0.1 and HSTS enabled) + +SSLProtocol all -SSLv2 -SSLv3 +SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA +SSLHonorCipherOrder on + +# HSTS (mod_headers is required) (15768000 seconds = 6 months) +Header always add Strict-Transport-Security "max-age=15768000" + + + + Require all granted + + + + + Options Indexes FollowSymLinks + AllowOverride None + + Require all granted + + +Alias /static /var/www/static + +BrowserMatch "MSIE [2-6]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 +# MSIE 7 and newer should be able to use keepalive +BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown + +ErrorLog "|/usr/bin/cronolog /var/log/apache2/%Y%m%d_error.log" +LogLevel warn +CustomLog "|/usr/bin/cronolog /var/log/apache2/%Y%m%d_access.log" combined + + \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/templates/celery/celerybeat.j2 b/provisioning/roles/regluit_prod/templates/celery/celerybeat.j2 new file mode 100644 index 00000000..d459ad8b --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/celery/celerybeat.j2 @@ -0,0 +1,35 @@ +# http://docs.celeryproject.org/en/latest/cookbook/daemonizing.html#generic-initd-celerybeat-example +# to be placed at /etc/defaults/celerybeat + +# Where to chdir at start. +CELERYBEAT_CHDIR="{{ project_path }}t/" + +# Extra arguments to celerybeat +#CELERYBEAT_OPTS="--schedule=/var/run/celerybeat-schedule" + +# Name of the celery config module.# +CELERY_CONFIG_MODULE="celeryconfig" + +# Name of the projects settings module. +export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}" + +# Path to celerybeat +CELERYBEAT="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celerybeat" + +# virtualenv to use +VIRTUALENV="{{ project_path }}/{{ virtualenv_name }}" + +#Full path to the PID file. Default is /var/run/celeryd.pid +CELERYBEAT_PIDFILE="/var/log/celerybeat/celerybeat.pid" + +#Full path to the celeryd log file. Default is /var/log/celeryd.log +CELERYBEAT_LOGFILE="/var/log/celerybeat/celerybeat.log" + +#Log level to use for celeryd. Default is INFO. +CELERYBEAT_LOG_LEVEL="INFO" + +#User to run celeryd as. Default is current user. +#CELERYBEAT_USER + +#Group to run celeryd as. Default is current user. +#CELERYBEAT_GROUP diff --git a/provisioning/roles/regluit_prod/templates/celery/celeryd.j2 b/provisioning/roles/regluit_prod/templates/celery/celeryd.j2 new file mode 100644 index 00000000..c918efb4 --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/celery/celeryd.j2 @@ -0,0 +1,9 @@ +CELERYD_NODES="w1" +CELERYD_CHDIR="{{ project_path }}/" +CELERYD_LOG_FILE="/var/log/celery/%n.log" +CELERYD_PID_FILE="/var/log/celery/%n.pid" +CELERYD="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd" +CELERYD_MULTI="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd_multi" + +VIRTUALENV_ACTIVATE="{{ project_path }}/{{ virtualenv_name }}/bin/activate" +export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}" diff --git a/provisioning/roles/regluit_prod/templates/common-old.py.j2 b/provisioning/roles/regluit_prod/templates/common-old.py.j2 new file mode 100644 index 00000000..57e97fe5 --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/common-old.py.j2 @@ -0,0 +1,13 @@ +import os + +# all the COMMON_KEYS +# copy this file to settings/keys/ and replace the dummy values with real ones +BOOXTREAM_API_KEY = os.environ.get('BOOXTREAM_API_KEY', '{{ booxtream_api_key }}') +BOOXTREAM_API_USER = os.environ.get('BOOXTREAM_API_USER', '{{ booxtream_api_user }}') +DROPBOX_KEY = os.environ.get('DROPBOX_KEY', '{{ dropbox_key }}') +GITHUB_PUBLIC_TOKEN = os.environ.get('GITHUB_PUBLIC_TOKEN', '{{ github_public_token }}') # 40 chars; null has lower limit +MAILCHIMP_API_KEY = os.environ.get('MAILCHIMP_API_KEY', '{{ mailchimp_api_key }}') # [32chars]-xx# +MAILCHIMP_NEWS_ID = os.environ.get('MAILCHIMP_NEWS_ID', '{{ mailchimp_news_id }}') +MOBIGEN_PASSWORD = os.environ.get('MOBIGEN_PASSWORD', '{{ mobigen_password }}') +MOBIGEN_URL = os.environ.get('MOBIGEN_URL', '{{ mobigen_url }}') # https://host/mobigen +MOBIGEN_USER_ID = os.environ.get('MOBIGEN_USER_ID', '{{ mobigen_user_id }}') diff --git a/provisioning/roles/regluit_prod/templates/common.py.j2 b/provisioning/roles/regluit_prod/templates/common.py.j2 new file mode 100644 index 00000000..6e2e938e --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/common.py.j2 @@ -0,0 +1,5 @@ +import os + +{% for key in common_keys %} +{{ key|upper }} = os.environ.get('{{ key|upper }}', '{{ common_keys[key] }}') +{% endfor %} diff --git a/provisioning/roles/regluit_prod/templates/host-old.py.j2 b/provisioning/roles/regluit_prod/templates/host-old.py.j2 new file mode 100644 index 00000000..b036d9c7 --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/host-old.py.j2 @@ -0,0 +1,47 @@ +# host.py +# copy this file to settings/keys/ and replace the dummy values with real ones +# or generate it from the ansible vault +import os + +# you can use this to generate a key: http://www.miniwebtool.com/django-secret-key-generator/ +SECRET_KEY = os.environ.get("SECRET_KEY", '{{ secret_key }}') + +# you'll need to register a GoogleBooks API key +# https://code.google.com/apis/console +GOOGLE_BOOKS_API_KEY = os.environ.get("GOOGLE_BOOKS_API_KEY", "{{ google_books_api_key }}") + +# +GOODREADS_API_KEY = os.environ.get("GOODREADS_API_KEY", "{{ goodreads_api_key }}") +GOODREADS_API_SECRET = os.environ.get("GOODREADS_API_SECRET", "{{ goodreads_api_secret }}") #43 chars + +# Amazon SES +# create with https://console.aws.amazon.com/ses/home?region=us-east-1#smtp-settings: +EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", '{{ email_host_user }}') +EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", '{{ email_host_password }}') + +# twitter auth +# you'll need to create a new Twitter application to fill in these blanks +# https://dev.twitter.com/apps/new +SOCIAL_AUTH_TWITTER_KEY = os.environ.get("SOCIAL_AUTH_TWITTER_KEY", '{{ social_auth_twitter_key }}') +SOCIAL_AUTH_TWITTER_SECRET = os.environ.get("SOCIAL_AUTH_TWITTER_SECRET", '{{ social_auth_twitter_secret }}') + +# support@icontact.nl +BOOXTREAM_API_KEY = os.environ.get("BOOXTREAM_API_KEY", "{{ booxtream_api_key }}") # 30 chars +BOOXTREAM_API_USER = os.environ.get("BOOXTREAM_API_USER", '{{ booxtream_api_user }}') + +# you'll need to create a new Facebook application to fill in these blanks +# https://developers.facebook.com/apps/ +SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get("SOCIAL_AUTH_FACEBOOK_KEY", '{{ social_auth_facebook_key }}') +SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get("SOCIAL_AUTH_FACEBOOK_SECRET", '{{ social_auth_facebook_secret }}') + +# https://console.developers.google.com/apis/credentials/oauthclient/ +# unglue.it (prod) SOCIAL_AUTH_GOOGLE_OAUTH2_KEY #2 +SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get("_KEY", '{{ social_auth_google_oauth2_key }}') +SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get("_SECRET", '{{ social_auth_google_oauth2_secret }}') + +AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", '{{ aws_access_key_id }}') +AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", '{{ aws_secret_access_key }}') # 40 chars + +DATABASE_USER = os.environ.get("DATABASE_USER", '{{ mysql_db_user }}') +DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD", '{{ mysql_db_pass }}') +DATABASE_HOST = os.environ.get("DATABASE_HOST", '{{ mysql_db_host }}') diff --git a/provisioning/roles/regluit_prod/templates/host.py.j2 b/provisioning/roles/regluit_prod/templates/host.py.j2 new file mode 100644 index 00000000..845c962f --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/host.py.j2 @@ -0,0 +1,5 @@ +import os + +{% for key in host_keys %} +{{ key|upper }} = os.environ.get('{{ key|upper }}', '{{ host_keys[key] }}') +{% endfor %} diff --git a/provisioning/roles/regluit_prod/templates/opt.pth.j2 b/provisioning/roles/regluit_prod/templates/opt.pth.j2 new file mode 100644 index 00000000..27d47a41 --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/opt.pth.j2 @@ -0,0 +1 @@ +/opt/ diff --git a/provisioning/roles/regluit_prod/templates/prod.py.j2 b/provisioning/roles/regluit_prod/templates/prod.py.j2 new file mode 100644 index 00000000..a46a9177 --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/prod.py.j2 @@ -0,0 +1,135 @@ +from .common import * + +ALLOWED_HOSTS = ['.unglue.it'] +DEBUG = False +TEMPLATES[0]['OPTIONS']['debug'] = DEBUG +# we are launched! +IS_PREVIEW = False + +SITE_ID = 1 + +ADMINS = ( + ('Raymond Yee', 'rdhyee+ungluebugs@gluejar.com'), + ('Eric Hellman', 'eric@gluejar.com'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': '{{ mysql_db_name }}', + 'USER': '{{ mysql_db_user }}', + 'PASSWORD': '{{ mysql_db_pass }}', + 'HOST': '{{ mysql_db_host }}', + 'PORT': '{{ mysql_db_port }}', + 'TEST_CHARSET': 'utf8', + } +} + +TIME_ZONE = 'America/New_York' + +# settings for outbout email +# if you have a gmail account you can use your email address and password + + +# Amazon SES + +EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend' +MAIL_USE_TLS = True +EMAIL_HOST = '{{ email_host }}' +EMAIL_PORT = '{{ email_port }}' +DEFAULT_FROM_EMAIL = '{{ default_from_email }}' + +# send celery log to Python logging +CELERYD_HIJACK_ROOT_LOGGER = False + +# Next step to try https +#BASE_URL = 'http://{{ server_name }}' +BASE_URL_SECURE = 'https://{{ server_name }}' +IPN_SECURE_URL = False + +# use redis for production queue +BROKER_TRANSPORT = '{{ broker_transport }}' +BROKER_HOST = '{{ broker_host }}' +BROKER_PORT = '{{ broker_port }}' +BROKER_VHOST = '{{ broker_vhost }}' + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': True, + 'formatters': { + 'brief': { + 'format': '%(asctime)s %(levelname)s %(name)s[%(funcName)s]: %(message)s', + }, + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler' + }, + 'null': { + 'level': 'DEBUG', + 'class': 'logging.NullHandler', + }, + 'file': { + 'level': 'INFO', + 'class': 'logging.handlers.RotatingFileHandler', + 'filename': join('/var/log/regluit', 'unglue.it.log'), + 'maxBytes': 1024*1024*5, # 5 MB + 'backupCount': 5, + 'formatter': 'brief', + }, + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + 'django.security.DisallowedHost': { + 'handlers': ['null'], + 'propagate': False, + }, + '': { + 'handlers': ['file'], + 'level': 'WARNING', + 'propagate': False, + }, + } +} + +STATIC_ROOT = '/var/www/static' +#CKEDITOR_UPLOAD_PATH = '/var/www/static/media/' +#CKEDITOR_UPLOAD_PREFIX = 'https://unglue.it/static/media/' + +# decide which of the period tasks to add to the schedule +CELERYBEAT_SCHEDULE['send_test_email'] = SEND_TEST_EMAIL_JOB +# update the statuses of campaigns +CELERYBEAT_SCHEDULE['update_active_campaign_statuses'] = UPDATE_ACTIVE_CAMPAIGN_STATUSES +CELERYBEAT_SCHEDULE['report_new_ebooks'] = EBOOK_NOTIFICATIONS_JOB +CELERYBEAT_SCHEDULE['notify_ending_soon'] = NOTIFY_ENDING_SOON_JOB +CELERYBEAT_SCHEDULE['update_account_statuses'] = UPDATE_ACCOUNT_STATUSES +CELERYBEAT_SCHEDULE['notify_expiring_accounts'] = NOTIFY_EXPIRING_ACCOUNTS +CELERYBEAT_SCHEDULE['refresh_acqs'] = REFRESH_ACQS_JOB +CELERYBEAT_SCHEDULE['refresh_acqs'] = NOTIFY_UNCLAIMED_GIFTS + +# set -- sandbox or production Amazon FPS? +#AMAZON_FPS_HOST = "fps.sandbox.amazonaws.com" +AMAZON_FPS_HOST = "fps.amazonaws.com" + +# local settings for maintenance mode +MAINTENANCE_MODE = False + +# Amazon keys to permit S3 access +# https://console.aws.amazon.com/iam/home?region=us-east-1#/users/s3user?section=security_credentials +DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage' + +# we should suppress Google Analytics outside of production +SHOW_GOOGLE_ANALYTICS = True + +# if settings/local.py exists, import those settings -- allows for dynamic generation of parameters such as DATABASES +try: + from regluit.settings.local import * +except ImportError: + pass diff --git a/provisioning/roles/regluit_prod/templates/prod.wsgi.j2 b/provisioning/roles/regluit_prod/templates/prod.wsgi.j2 new file mode 100644 index 00000000..096c5f4e --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/prod.wsgi.j2 @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "regluit.settings.prod") +os.environ['CELERY_LOADER'] = 'django' + +{% for key in host_keys %} +os.environ['{{ key|upper }}'] = '{{ host_keys[key] }}' +{% endfor %} + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() \ No newline at end of file diff --git a/provisioning/roles/regluit_prod/templates/regluit.pth.j2 b/provisioning/roles/regluit_prod/templates/regluit.pth.j2 new file mode 100644 index 00000000..8964ac81 --- /dev/null +++ b/provisioning/roles/regluit_prod/templates/regluit.pth.j2 @@ -0,0 +1 @@ +{{ project_path }}/ diff --git a/provisioning/setup-prod.retry b/provisioning/setup-prod.retry new file mode 100644 index 00000000..d3b06b7c --- /dev/null +++ b/provisioning/setup-prod.retry @@ -0,0 +1 @@ +regluit-prod diff --git a/provisioning/setup-prod.yml b/provisioning/setup-prod.yml new file mode 100644 index 00000000..a792de6b --- /dev/null +++ b/provisioning/setup-prod.yml @@ -0,0 +1,18 @@ +- hosts: regluit-prod + gather_facts: false + tasks: + # Need to install python2.7 and pip first so Ansible will function + # This is due to Ubuntu 16 shipping with Python3 by default + - name: Install python2.7 and pip + become: true + raw: bash -c "apt -qqy update && apt install -qqy python2.7-dev python-pip" + register: output + changed_when: output.stdout != "" + + - name: Gathering Facts + setup: + + - include_role: + name: regluit_prod + + \ No newline at end of file diff --git a/provisioning/setup-regluit.yml b/provisioning/setup-regluit.yml new file mode 100644 index 00000000..8bb3776b --- /dev/null +++ b/provisioning/setup-regluit.yml @@ -0,0 +1,6 @@ +--- +- hosts: regluit-local + gather_facts: false + roles: + - regluit_common + - regluit_dev diff --git a/utils/crypto.py b/utils/encryption.py similarity index 100% rename from utils/crypto.py rename to utils/encryption.py diff --git a/vagrant/group_vars/all/misc.yml b/vagrant/group_vars/all/misc.yml index c08529f2..2d4a280a 100644 --- a/vagrant/group_vars/all/misc.yml +++ b/vagrant/group_vars/all/misc.yml @@ -1,11 +1,11 @@ $ANSIBLE_VAULT;1.1;AES256 -63613831616639376633626266303462633762313365343031313561363336333536303436623033 -6431323039346335366131353366616466663932363365320a343964663464313835663930386236 -64313434633233613764393834646431666632373033636561373833623931363033396235653031 -6237326633343230330a303432623634363363343036363534396162303532326335633532663065 -39336337653362346134396266353639643530643430363963663633623163373336633966343038 -66633563356332663136636434323635633164313232343337346335623337633337316533313531 -38306332303562383663303033653237386563653339653230313939623435663166653364653862 -65373863306531633963653639303033343733653339656563656264633362663238663136643733 -39373565353639383830333462393935353165633236346238613334643863336637326161636166 -6162303863363232643039313835313036363865663531363230 +34396634353236366232316262326532383330346466656632396266363962363330323331656538 +6463386133646665623738313130636139363361323839350a653766666239353962633534353261 +37343761653238333833316131373035663266336336383564613230366639663861656631646362 +3462383738373136630a303131383066613030653564316335656332373534396336323538393933 +39383232613833393763663564633738376436626665623333663163306630393866343236613230 +66376334653631663365323432363364303431326336623266376535393338393733643964363462 +63333031376134623632383865653136393766346637346563313231393766363331656336663639 +35363461646561616136616334306232376165363364323931313539373438613564633630376237 +66323936356136646233373662323030376130356337326263353239323338653330623830663432 +6434393837656430346632383766636664613436373339396430 diff --git a/vagrant/group_vars/all/secrets.yml b/vagrant/group_vars/all/secrets.yml index d4a96e78..47820687 100644 --- a/vagrant/group_vars/all/secrets.yml +++ b/vagrant/group_vars/all/secrets.yml @@ -1,51 +1,51 @@ $ANSIBLE_VAULT;1.1;AES256 -63376563643062623466613335633730323031653736643437643030303533383931666434323939 -3266633436313635643463333266356238316638326131610a653336303661326334323561623239 -65623834633736663861343464333764303865663934303533333031343934333635616333643631 -3933383131353062630a633133353430386437626130656632393230636664376438613862303466 -66343337303961303361353030313936626363383465316166316663643830313164646661363366 -66656630323437643031363237633439366434666537396464336364373134383061623364636635 -31393435326337373162333365386465633730323135383364383433366664353938303962313461 -61633835393963646666376562633731626639313438326235306335653639666635386566343033 -36383064653634613065303538346638363666326336643631616636623632376662323037633165 -32633662636531643366343963663439313439636335336435616666633863323433643930666536 -30623234313838616461383534663230616364336131383763316235356265363964636539316637 -61376433306366346362303439303665333961393239373263373365306363336334623536353031 -61636339353561303532383833336164346538396139373835633162323339333732373431613035 -62333739373832623762356364383035343937656337666439323830663235666637326134346531 -66386135323064333732663136396431616563653731343134363262373639333836623033656536 -38653931346337666566336331363631666238666638353237663065653164343936636239343631 -62636339396332663637643239376335343731643764343666356361623239383462313936366363 -32616638653666666638316563656366666361353538303133656433376637663532313666343631 -63633436336137653339653364616532333434623036396439343433613361626231613331373931 -64343232313839383332353036633633383762316531383936393539316531316336636537666439 -33613166613733346336643932363263663833366533623965623039313036373230396135343663 -66653336313437336561333630393365653133636263333031356562623332623733616464333262 -35333535396337616461353361616337613138363239656162323232346436336233633335376666 -63626661373639306665613431393735343937616539336233666235343936653932366337326663 -33353930653965623661383265643837306637363231656435663030393562623438623361353666 -36626635323837363733353365373738646230303436343834636666373165653937333130343637 -31666566643434653663626531383730666238306438656133303862626538613339626437633432 -64393432333834623339393631363932353862646332313062636565326135636138333931333431 -64633937356630326666373939343635323263373934306330393032316630646333363239313137 -65383666663063356430663965336463393537363266636431633362343263666234323463653532 -30376262656335653662656366636336336135626130303835326432366438393962616266373435 -39613234326136623263356131376239313136653131326632343739313137653833316434656265 -30323863383639363462613034353062393964333130656161306633306566646233356537313162 -65376237303961333239303630313831303232643831383036643166343164363934323138353234 -33623130383339343162636239343234393731626530326164643438633239343738306236623433 -37636662353263373866656564316334303736336566336636653937663566343261333335333437 -62313833353235393131326430323263383861366230663639363661383362363438373432346663 -62643166363633633134303836383239386236386361376533353330333930633530333139666462 -63623361356134333337643634393461343635363232313435656137303731326461653330613831 -66613536666635313539643130373132623965333863343930363761613031306664333732393564 -34333937326234383833306233386638323263323430613863346436643030353732356261643834 -62343230633034363839373965646133353238346261373538313833323264616531313965376537 -32646166326135306134356262353461626337663137323335613339646532636663326462393936 -30316265636335336138383930313138306366383766653866613532626366373463613436303638 -31333738306164613031626435373966323361626564666537396539313832613038363865366534 -62656565316466393366303137646431303231626534613031316561336233353137353265623032 -32616134366439363630376666343937633462613731613961343862303639373135373466363663 -34663235333431323764613330303539323164313332313331613761306439623232396436323138 -35623265613335636430323335313230373865633331303633613632306431323339396165626135 -3662393265643861393433333230353233366330646435343361 +38353435396232353338653362653465343063393836633332633964663162363636316433396365 +3336316136626134653262626630663738333938666336330a626562646335323264626363316233 +62383131353536323166353364633437383333663434653037353964646662633865323466306237 +3336306364653366320a323464383061353862663932623461346230316364396530653564353762 +33363864663730643265396565363430376564386164366163323266393735633830363534353665 +31376233393136306365383366333866383962313864376561333964623639623834373931396133 +31646665313165376266336132663833663436633165393536316262373635353837306365363964 +38656539313935366663336539376334313863633439343664353530393336383064623533336264 +34346630643737643938373366383432303139653566306163333463366465623465303862616361 +61363139613265636432616533656564386231323066623863663463313336626435323433343337 +31626530626132646262366334643261626431643261633334393262636137643935376461643739 +38633631626366303934393139356166633536333634396163333164306532373765656138393464 +39623636353034343363396361383837663863313465636134616333666563666534653930626331 +65633536383230653665356233323330666439643665396335303566366230646366356534663732 +30313835323633306130343865626131383032666236663362633733383235643239383765663332 +32643332313361353736313035653137323239616635653662386435373939386636653138393036 +38396231623635316633333366646339336662313164656634363536376163333631353031373232 +37643636303934313664633765353562343666353961643237316461383131343566326466663936 +32613933303430633165363339373433363637343733633833356339373965336131666234373737 +33653763326461343164313663633361303261333737326266663030646136643234313263376432 +33636332376634313364383463643030333462323266383263643535393061313665636637323266 +62626334303936626535656431366339393561356461393862633464336534386665623735383862 +37336232336662633331386661643131343663356133643838636231396336303364393562336139 +30623030316365303937333037386362613065636161336530613637353737323535636138366263 +30303533353531396135663139646566646631643533306165383364643764656330666134366633 +64353333333065663238353666303637366162346535656534666465336630323764303639616564 +63646638646566663033373263653062343466363364333537623661643331666664343065656633 +32356239316638613264303939363830373030353263613863356465663538666638333462336234 +65653563306562663530383334643763353464643363356462343863653965623634663338333136 +31366531383837396564353134333232376630613063613134393038366631616365366439616263 +36363231396665626263373830383330393432633934626363393866353538663433343563323631 +65346430666666333237366162636363356462313165383233313438353431636539663131386134 +39626136613935393265363534336265653435656333386363303735613336633062663131396336 +65616339376561383633636362323530323061356134303365303234383063336261643330363363 +39396332666532353563363966326266333632313164643965343538633763376466353864383435 +34366266666162306334613262663861646538346139343631343139353234333661386234666431 +39353038373434363130633435633161623565333062343734626239653434383035653361393865 +64646135353236313261303633346161393636323531326334393036663137626365303934346337 +33336136366534343238623262313064356634333661356339383462303037383630656631643762 +38346439353338616165323562633436623131623532313663323131303737353734336234386164 +37343465636332663363396536393266613235333762363538373261316263653135663931333962 +31613630303266363265623363393364636437316465646532623264326239346531363165346566 +34333831666236643636663738383363616231333166336334663035336639666165303965633064 +33306434363730633830346535326565643563306338386235313633363631353666393161313934 +63346531653062336666336366356330646566393563356464346436656333363962383562363463 +64313466633064316331646130366333326438633662323034383037396363643861353736336333 +66663531373230386330393065663762653932646561373962633034343635333265313964343965 +33663239316334623636646530363565636235666536646132303533663230396363313732373063 +37663333646639383037336333343438643933643238396236653935396663303163363962633237 +3038323032383666326138306366633063636366363534393333 diff --git a/vagrant/host_vars/please/secrets.yml b/vagrant/host_vars/please/secrets.yml index 1c3921a0..ae1a221d 100644 --- a/vagrant/host_vars/please/secrets.yml +++ b/vagrant/host_vars/please/secrets.yml @@ -1,93 +1,93 @@ $ANSIBLE_VAULT;1.1;AES256 -38386461333437313133643631373538633664303964383463643764363236343164383636653035 -3966626566393633313332623565383763643434383930360a323663363833646139343039323139 -34333837383866646565346561313032393334363966383564666662326366633532623132626435 -6263306636633738300a613362393561363931356634333430366164616539353737646438363962 -31356266643864393332343962653364363836363235343932623839363562313966353337366463 -32333832663536633731393666383966663365646662663664366330326330343564316238346462 -64316231373230393530306563323136626631633137323636383432366235306437623930663666 -39613830326339353335653537356262313332383765313438623236326131316466326631366336 -31653338646666313533646365303537636439313438623266383231376231613534303630383338 -37363461373262623732613536323362343036373238313434393666313033353032633830663532 -62353365343937333133306138626337626536386465633536613331343635343931356431303964 -63636136643938646332633833623733343835366133323832393236343330373632626663656231 -37653537663739336432313563643865663238303535636463623339313161626138313961346239 -36316631353935613265616137363962333039663138366439346461373365633464333265393435 -30633436633533323038386664666439313939373033333134396437386335366633306164363831 -31363561333633343464646566643361366365306264613536363334623663626236306562393664 -37383163373538306632616330326433393461323961353565373561393361656661333962663136 -64343761613134363637316466393161326264396263346264656263613931373465633030306265 -61353961356230316361316566643537333031343635663837323238356231356234313839306331 -61383863323766656461653737363533336333333635386662343563333233386131623734316139 -61666661323962303631646365363735363135343733653265646532613166313962663230386638 -30343563313237373039623933313161313465343337366331303761626664306163353632626465 -66643964323638356462316635323264376235323734633732393538643032343461646262663235 -35313934303362386335306264346231353431333437383038643233346336396465336333326364 -63656135363764616538383666366131323464623337343939356665376366363161626330393131 -34336463336566646138336562633931353531366635326632306335303865363232373964663664 -31363965386431363961343962666538633837663933623362653137363365623037623631626537 -65366534643533346630393837383130613961653636613835643665346337633363613732383234 -36626164626461356238646135353338393463333839323964643966643463353264393362616466 -32336338373936343733393436333536383562613365323538633163656634333536383930643532 -64383834396166343931346166646234343231643665623836346131663238663365613063623161 -34343131323063366434613164383761366265623061646665363964346230313038306664363561 -33316664633861313632343161613236343934386166626334666632356266353966663163303731 -30373166363637663131613564303634373337626538626665303139656362383935383535663366 -66663437323039343262333636623363366231313366626434383039336231323938666633303663 -63326264373065613539323433646163653334613733323536633862343535306165633731343361 -64366136663535306433636338653763653030643837633830343034363361363132666132386633 -63393331396165366239313637303836313737326531646635613036373436346239383333336336 -31623434333336643863303334313539336533636439393738353766313338313161336239386363 -64353032633934613533646532613961346531353664333230613036393737333966373437363863 -36626139333030326134386164653931393432323731373562343735303737376532613534396463 -32346432313361643235653165376630316631616463336238316234626231396364303364643136 -35393165333439373336323630636138333730316266336261316637613738383639343661373239 -64336535306465333161346637346636643034316236353664653464323061323834366633653561 -37663730353531373630613034643464333933663331393337303335313631383134353330323238 -63363030386236323738383661633366316265663566613331386166633436666564303738356263 -34356166656465656230336166636533643866666565646336626338643135633236353033626230 -66646230303262626635653665336333383831313232353565313638396462353035376137666230 -36313931626665316234346335343838363533623838353263313732633735653861633936633239 -37363139666137623665376131666636306233363861363931333034383063656335663333656134 -37323461373261343563663239623533313532386539646562333864633337393966613532336265 -62646161633830303630356636356138383962633935386335336432663461613039333333666263 -31303431336266616463393238663662643961656536353238613965646138316630663934313235 -32353261346337346438623732383036393961356332363838316266313566623437336263393836 -37353939626536326538643962363731373833356532366232323034393137373463383630646165 -35633439613330663065356630353631326136363633666233343837633433626136623332303263 -33306435643734633865316565363832376137616231666562306335643637663132316435383765 -34666638343031323762653363333062363034626134626463636331383331353939613865366633 -37333639626136373964366234393939633664656535306539646362656437636539643036363364 -32343939323763303966343230616136643132623132333230613663363931363832326661356364 -39363231643036633464643539346362376566343933393861643335626338656335306434393464 -63633537656166653638333532333633626439306436333736316465646538343137326430613934 -63313538373435353535323734616562323631393763313065336461363237393331616330393435 -62366238373532313132396132323561643866396365373335326462303163613339666536396630 -63646564373431333734633832316633316531623730356462663232636662353131646265376435 -65353562613066353830623239333265346362653861316432636361613134613366633735666138 -31346265383164623062363431306664383436653265343434326366653066306630323635633136 -64366163383161303735613935653231356635316338333132363836313165333932653635643062 -63633530636631643565333765666438343231326439303239303530306436323365646639346433 -66373161643164613861323661303730653635306662366234323132346533643164303338353136 -37353664636239663066323265313330303631396562646636623136663836643236333139656434 -66313531373161333038393161383663313062356439323839663139393736633637386332633938 -63313737393166316361623762303237623835336534353764373139666539343766333461373437 -39356438313039306333396262373330323561343065653765646566653831336363646638333637 -61326662353765326566663266646365336533636437383862326561663032366230613764313136 -64303232396534303136613931376633323937376464373133646636336263643462646365333164 -32623833363264376233316136633666366435303635386330636238343139316136306231396533 -35316438623539393362366363353635363732323839373063636531363462383334623365656436 -36383335333561326333626532653132663766363231353966396633303333343165653838663262 -66376666626135376564393235616130393436613064653130616362613031383532313633313936 -38333532376638383461643332353837363061656632353430376163393431623032336530643234 -62313331323561343166653636366461613834326534396231326163303462303235663162626462 -63333766363330633066386466346235366335383266386561643336306536363034396231373137 -31376261663937393439386462613531616366613362623863326235326531663337316531623831 -64666636313035323235323236393238346261343765613639346163363430386130326365313331 -38613365623438383339613664643037316431636632393066363531316631336264623930346532 -31636333616139636236326464323333376236393862646333656464653063656263303433623164 -35636161623463353363636334383266356236656163633064303231663430343430306131333662 -63633131653262346636633632646638356263306238616135393938393238303461303965313361 -39656138373639373335316362336266313838396661343933633162376237616635363764623630 -36336666333531353237323263356664303932616136373736326361623733336331343136303637 -31336630613031373564 +64346437633164303231353763353632353638376565623935303562383939306134356238643662 +3863623565353533333032343339616464393235393735640a616438353833353930663639393262 +61303932623163343666383238386137343631353032333339376339613464626263346530376166 +3333663433643530300a366165343831343435396134343162656432313035626333396465373066 +37623635396630363335653438643037303662643733386262356134633563326536303064623164 +35356339643466613931636430376561616438616535653936316238626430333637313966333330 +65653033386636623538316162663539393064383061653163343766363237626438353662373661 +38343966326661323466393634343561666463623766663331346361643538393234336163386462 +38343664323166616332353637343064396332333663353165313661366134333239316166313761 +33346161316130353432386132373633356430306237393937326432396630333239306339643239 +66306133386131376366353836326164613030323133373561363334623964346265363861343833 +31663963313336323463643931663364663437616335653534663130623137613638336333663333 +36353331616466386439633363383861323232626562386362376262356338663935386434623663 +65653833623163376231323232316239353432616663346637616434313931386265633933333339 +30343662316365346533316333636131303434633039346139373032373533313164346232623734 +39653262633432383063313231383465633039653237646235663466386230663135376330333432 +35643931666135353234396439303664376236646238363335303762653335316266376363633130 +61396665333432313461653666336637623039383439316332333034346530383763623166626530 +61383036393530633636383764653937323463656563306131666130636161366531313838633438 +66313261343165333430343233393861646138373931363831336636663239363535306533623034 +34306232613932323065316630363262373437626230323563626339306630633034663765366161 +39396535303262653264633135656264386539363239636630626330343864663635616530323062 +31333365393538346432313335616138316538663237306364656232333137666165313861376361 +39383830336637326466316432303232323165303633343866623963343234636439623434643435 +38633361356238313263663235323237643733646637313035316462393935396562376366386538 +38396665303831393838663435353435663631383062326533353236396439383531623464636537 +34356239663635373439393137346430386135306166313931313665353631613930663663313862 +66616164616463663963383263626333383962373262643837636530366230303562383938333961 +64323565393830646633383262313466363736646637396336343236333439396638643931636162 +63313338366332623131386539353435653234336632663631383939356161346664656265643563 +33633661393566303835643530616465316530613161363663313631613436633461323861313138 +61346665363130376639356235633031646633303838393963333030353962333466626633616131 +32643762623630613237313535636337306636356530336339663932333361313733333861306436 +66346631656665626439353566393034303833326630616532656434396639373335353162343936 +64633665613139623435303164363536326630373838613261616534326534666631613962653962 +35333264396235343931633066653763356666393065653933353032623231366564643939363437 +64646631613339326432336363626538393162663161646661333532383462663733383237636230 +32613661653931346231613137353731633833303630356532623635313538386364663366303261 +38383761336530326663613231353164343535613962633835643462366262336137633162333762 +37353964346562626133616235363661343166613062353934636132363631306266323031646637 +31356633653766376137663139373362373631653338613263306462343130613461333230646461 +33646132663135626231613937353065373034383131353733333131313930616235376134643663 +65366638636366646363386130663838306331623035626334373639313539666661663364316532 +65313334333965336531353233336135303439653538633266393065656235643166373432346362 +63653864376634353336353338353964643931353763646665363034316532623031663762666663 +32353934643961393536303864373761356534333462343866333161396236326531383563613435 +33333965313062366436666337323831653361383530343130643065613232356263393334386234 +63386162343838363465383037326163643165323038343936303061653837373934343662656337 +38353530666366303765336439383562666666623164336233333532306530393437626461373935 +61363830376266666438383766303832393630623033666565363432613631343239326563366136 +64666539666134373430333537343963623366633039336339626437636638323262373431333936 +63633932346539376463336232623565306262656239366433313264376538646365653065316534 +34623635623336636438373232383063393166653932353331386162643332326265383837666432 +63623262353434333437333863393930336337616337626337623531626462356538663531366432 +34363030343363316461393866323034353432656636326164333532626534363434313635663362 +37626435303134353435366437393435633565656166646165633531323965623234623035346236 +35346239333133313663643231356233303530303034313230333039613963366237373961623036 +31313438356239336437653035633133626166633066643663333935653038356638393461316261 +34343861633664656263656133326333653065393731346537613064393565303861613433386230 +35646165363662386538653139656264616565313562363534376637396432313233343133633038 +64343631613563623939303234313631333533623033376633376330643666623563376564326333 +65326663386664613465363161353431653465663333633436343031323464383533313532316465 +64363835663835363933666230353362636635333063663731643139633939626234656336333836 +34376338343237636433313939623036346635643735373735626530333761376436396238393266 +38646163653265303732623962303733346161646437366135633565373432616261353964633730 +33313935333532333336623631366466623231396538373134616137643333616437396534373837 +61633065613864653163333738626664303036353733306464353263366233633731393664383065 +66363533643363363365653662323038383864383664636137613163323932646433353066663331 +32386562633532366435393833623537626664396164303830653539373362376330323463316436 +32303830323332333131366164316164303836383238643636373838666462366233626661336461 +31623235323165303339303737343363396136656161666531653866316461363439303737363665 +34373235356632326562343563633735373834626665396362353732636232316139326665383063 +66653336303036363864663533633262363937373566306135626430653065393638656662633233 +32643938663030363436633463646562653961383332306462353933396335333765303936366230 +35396266653135346334323632633235626663626330343063666233643136343435383366393233 +33333761333937373164613861353039393633616361613339366633643439386365316162393264 +38313035613033626330323535666531323939313437383666323730343065366138303930643362 +36663863623534633930346336343761383632633737386332623533363632333262616330613063 +33333765633335636132646663306431313138356538366464643062663032343830653131633932 +65343265373939303433646333336133313132346535363064343261353463666137393362303862 +37363633336430666236646161643863633932343564353937386463366561613239656638666536 +34303961306333303938373666316637393964386231363736663731306435353833373032636135 +33303065383235363639383031323431363764306636633435323638616666313135633135303065 +64303531323030323430663762396132373037303363366333366639303164643335393861343035 +39356363623466633638633663393734363534313531356361663564376330343263393066353064 +31323965386231393736393631626438616635666130333630343461303339356537333165306338 +62643765656638626162356236383163363863653863613437633634323461313063623230323063 +38346131303737643233313435303361616165663138326431363361613536366366643831333362 +61383236613438373862373739656661323537616463386466333035646166383065343263343339 +36353233363266633435366630303463393430316134313965353262626631396230396462353030 +66653234343439353061623738663830663937363932623530653962633138323365623766386365 +31303933636438653532 diff --git a/vagrant/host_vars/prod/secrets.yml b/vagrant/host_vars/prod/secrets.yml index a71118d3..e30172a9 100644 --- a/vagrant/host_vars/prod/secrets.yml +++ b/vagrant/host_vars/prod/secrets.yml @@ -1,159 +1,159 @@ $ANSIBLE_VAULT;1.1;AES256 -38346539303366323035383961646532326632643533366661623764633665326530326262396532 -3239366336626230653262336661396465393364646234610a643261613233653431393763653035 -66343232326133356264363862353439353961363637616462376334616437343037643831646339 -3135633930303338620a613133343161373033666134653762373431656331633330303638346366 -65366466376138646535373438356335643530656564393234633731323336653339616161663961 -36363363643863313731343464373239336364333434353232636238383463353366303534396664 -37653061393863383839636132343130363837613835333934623131343562383362386339393235 -30336438316535633438393235663961616531386631666561643438616532363733356463343030 -66336561336239373530356336303935363137666436346563613065316533363339303863626430 -62373738386531386336323561643139303931353432366137396463313335323163326362343737 -61643466623838656136356137623535666363353864353832616633633964303765653838636336 -61306232353566353265353131383031306665373365336561666365373835346539383634336266 -66356232316364643036316463396564323436393463633839633538366234373563353465643934 -32383334383930623937346538346534366335663430623731366231313764643437363739363734 -32323939323836396137313365326534343834623536333432626238313232383233653661303464 -64316163653436383630323739636566663234336331666430333638666261623861323334613737 -39383866666132313963373338313864643866396261373664663134623862616665346435393030 -34356130353564303139393835333332393662626338303461376338396465326437636436383038 -62336362373138326633383866333738303262316334663335623530366330333665613039353466 -39303239346436326239386461636266313364656335643331623738663439393234383939306662 -63663231303161323066663333336137323436313337323938353536303736323639636138316361 -64396138363232393861653464366661666361646263623430376361353463643634623739643939 -30623934346135616261646662393339316536303836343130383365656339373231653633383730 -33333930653261306333666631626633313162626639353935343934663336336433613165303863 -64376364323062656161616538643865613535623166363863396133343434643663633765373535 -64316533356438373534366330646262643361363865333733333730303633663639626231633866 -62323835346264316263323035343437356430626437343564396164663961613236383637353236 -39323861343231646564653834386637653436323561336661663334636361653861343863643164 -61646666623436633661383530326563356534323166333465616236343930613839346637326662 -38643235656133366566663364653732343132386337383063613364636462643463393536356532 -66323738356635333161353535386234343631313433336237316665376639613861663864646438 -36633233333632643231663765346235376162363962346334653330663036626436646366353263 -34373562616334383366306531376134643666646164663964663634613731313139643839366630 -31623339376464323437653165666234373561306234643731356665613636363639323866306662 -38366533353962386664393634386266393163323466336633656132616431306631643463626532 -34663263303434613064373532326232636266336266626661663963616335353433306336653237 -34326633623333633961343361316665346235333637383239326333353038306566346139306361 -31323030393632363765646534306266633164383435383666313464613863353662663964386635 -32613830386261333635376538656138636639633031313233323839353961646432303439636437 -63326166336535393565343734616137626437303136613432653337656164323164383730653066 -34633831643266343736616437633236343061386162656432393035323863366566303365646262 -64383561626164373166376131663763393135336166316539373230313461316133633238343361 -31323366613730363766373662376636386339383435393033346232663632636131343134333065 -38656335386462366162306433633261623263383036316365343861666137633162623232333133 -34386665373930636337663063376439616131363961343833616437333539616566323363313134 -35383834613065313231363133633937306638316231343765306436316433616563653862376335 -36623933633061376132616263383632656231303465656132393533646261303766383532633538 -32333139323934623133666662643263646438613332613664323463653164353366373166356135 -63323131303836613638336435333937613564623138376234393635396538623536623762653234 -63646337636638653964663131626534313437333461623933373334396133353734316663356365 -38643066316261313366353938333765313731383039353731383137626531633633343031623732 -36313232326136393761626236643366323031393634323237623632343163386565313363613738 -61616439656637636562333232363832363636663935636435336537313133666633656134643135 -64336634313966343262393930626637623537366532363563366633306134356438613839386632 -34623537646235363930396137313363646266376465653539316566623365373237323263376366 -64356139373330313937373861353739373738613164396639623336306262386463373462316663 -66643961383764653337393031363262656139383536353862356530326231653739653730656330 -61653830663932666533323461663262383066633135343439346261653663663038623335666435 -34373531336663316437633236666237333036323830653932666563353239623130643061393363 -62393135313938326265343334646333643739343662613432386239333365313963646233383764 -33613865343561336635333237373861323637323639386431353766633061616566643763653365 -63346530623263376665303635306635376138376530373933343263666339373637653337656439 -32326137383364343332323730626461666431333164343130633437383730653138323632336330 -62636431633734643732336532633139396535306463373431376262313533346632643465646332 -33303037343231643737643763613164636538396137356538373962386564656364636535656633 -35623765393633653063343938376331373336653464326335623331306666656366306139326465 -66333833653439363830636538616462363632383831626532626539363134333531346161343166 -32323833656333626633363664396463376665383239353362353531323730633761363332623034 -33386133663936623938643661333936653463313864323864343834383134336339656334353432 -35623631376532666534336432646563323037363637333735653961653261613963643335353061 -38663161383432653333333261393866656366386334333933383965636161616633393835646530 -33323963306365646138623063333039386666636263366536316232353633643739303631663338 -35333961343963663639633865343138373438363939356662373932373930313931373164383865 -38653364306165656439643866343863383735386265353131396261336536646439313339613635 -30643436616539643632366133336330363761336164396662656236613331643931633434653638 -37646239613833333836656362323338306136626337303935623461366664663532333961666638 -66636432666336663363376133326637646566326239373934336562636235346133353734313964 -38643538373530646461346265643663333263396262383764396466393664663637336535396333 -38663237326265333162363734636630653739313464383364316432303761363437353964363066 -64376463306639623266346437623637363234616131646230366438356633383662366130313533 -37643132303239643731663635303761373931646537633533613162326536346362356636373364 -31636461623435396438373235613066376565626566353766656437623631653536663934636365 -63316235323134326432343038373839326264363161653730613265366666633534353262643865 -34316130626230373733656631376137346665366336666635346664633334373134363930386538 -33353835383261343334366133393263326631326537353432666434323531326332303937393438 -38623234396263343435303063303161646237353937353464306231373435643239663764373264 -63366662636434363031366664666431663238346666323262383463616138643265336363343232 -30353235366437643865633964323962343330303539613963633131363333396435346166636434 -66383439636561653265646131613537313733656135623034383931346564666135336434393965 -34353364636665323361323636343766303265393664343033616531653535353333663939663838 -64373939343934396235666532343431646434313237326234353362356230653165633864336537 -64663039343066343364313531353536323338623562373261343362643063313139623262323935 -38616631393339343265386466393161653862336637303638383438383563646161363530626435 -34313132333436356136396130336136323235386261666264656564303733653039393465666665 -38626661666131343837346436616437663738353733663661366462323461333636636539393639 -35383934636666646335366563363462376433616161376162333139323030396131623663356630 -38663563613431646532303634373739366266613439383436373465346338366334646633663963 -32623234666565316564633362323061626638646264656237633266626661653464353866393964 -34646461366639316431653136363761663837373333393164323861636136653661383931616464 -37363931336234613734336362363865663336326163386236366237303434326566663935633838 -32383264373435353762363030353236333130616636656539373438633134306162356536396338 -37623038633330346134333438613864636333613363313266656263653334313430346265633235 -35333936346262316535653234373430373431663365623865613061343939383837373064393766 -62366465343238386332613465613933303537383137623137366336303462386236333237663435 -64613839316431363734303438616561356634623237626133326633316263303665626430356661 -39306432613237376666306163613063323431646631623261353035323761656631613131633466 -30383162323266623162653739666264363462353063663837313866653232613732616634383563 -65656433616461393839626335653361386466626266623037636231623230376561396236646234 -30636633633561326562363365326536333530313134313535323032636361353637323465313334 -33663436383466363065393237306533643739366133313961656636613836343162316466333233 -31336533363162623535333363376262383038323065386563613539383565336635656635343932 -65666130383336313830313538666138633861306232643437393030646461636163373261666337 -62626633303432376531653333353764383533383465316135313362373433613631336632626232 -65396337306665396238353266306134396466623338393365313634373064313334653235336133 -31643963623338303135363537323137623936666565316236653430306232623830353266303330 -62323466316631316433356139643333383461336134333734303637316463666330613030356134 -35623263663066653963653933346433303534343630313933613439653830613131393162643961 -65643133373664633061316236623962326131303437663836383531396131356633383833636563 -61373738386438626139303561373235633363326563303737613430663866663936343736376137 -62353634613337666539333265336630306565643037363533663966393134346661643030353534 -36313938633732323265633563313339393564356132346664373163313662333732613736633130 -33636439643937333536363039396561326333376535363134326461333239393133393563326532 -33393062306539336163316631306539363939656663663136666561333465313462383632313330 -31323331316336373164393962646665346438653637306366366563323331366439663566653734 -62336562613738623564663632393163626632643865616162643566326565326430373661633837 -32336435356663373738383734613937363334333430353630646130666131656664653463386563 -33343564666163316532663737333961333963396162663561316135313539393736316665613334 -30373466613633636465363533366262626261626137323937656165323535383539383461363264 -31356161313332613234343734626565313731303730623063646664343364366531613935333365 -31386262633538386132333333303937643039363738343835663837363135303637386439386439 -32336535313436666132646133653866623731383236646534303765616439313665303137636430 -32333038343132373433313339656662653361316639336166643333333530653365353036343363 -33613131373963313630653363313636636339376264383730663862346233613434656638333935 -32333433626461396137636165393432636533303961386432343666333266623933363562653164 -39613237366437643134363433386339623839363531363763343735636238333464373033343064 -30626533356632613732303835623764363664333631623665643634336463363934393339393061 -33653433643732616633343564656634316632343838636530396331333163613265626334373437 -34653730626563633864363065383431333466653362643630353839333035393961643739393034 -65616261303864343332333163633735326131313762613335646365343135616166646238353036 -61336536613661383837313633613065313937393939643238346538626633623139356661376335 -30386533376631313732646533326562383332656336613537303432363331653764396331653438 -62323035346230356562363032393032336632663363393331333130316430663830303934666636 -64326162343836326330393130343737343633613161653731306535313637343932306339663539 -35616530326565656161313764663866366163383539643631663939363836303538303966616361 -30643235356537326132646432396665323331383961343162393964373364646634623935656564 -37383831303661316665373461306361666536626163633238366134336662663539313966376230 -32656433346631316638656362313535633630303938323332346135323162633831313736616536 -62613733383763613235383932623239663666316337316164333333626637616433373561366332 -32616261626139393830623162373639356533393439653366363266336538366166623330346361 -37653865356235356637643832396334303631633633366332353035313239333664646431363264 -38356437623431396665663061316630663662376436646634333930306238323533373538353466 -31323565313434353635333334333536356438623231393237303032356462303030396166666330 -34376463356437396635343062353034666438383733383066383333326235636436396633393532 -32653662343732396635303936343531383838323832646236333239653036633835316635343638 -61306138386364633137303237323265633737396537306435343161646139326238623938316436 -30613638323563396232323464633430393331646130336164386463303337616366663262623833 -61623833633338333438373839643361616165633762343333333864386235363537323732356536 -3931643361643034346432333064646435323030363763353431 +37303235636630316435383233653430366438623337383033636361383766666232616330303263 +3138326465636535373638353765616237306265656639620a343362663063326666313237653263 +65383565353338303137316563346636356535616365343762633762643136653736646131626264 +3132633030623562390a663936353138313262653431336238656662366462373961393739373639 +35616533346132346462663633356636363134363737663834316466393435313366666138376435 +32323862663864616463346239663432646430643765386633643432356462333263386665326438 +31346632636166323163323730343937336563313235396265393261326339636263316438396461 +38316238633932326664386235313365613430313761646162383265613030356434633631336365 +62323830346631656635623438646162323136633038643233663963376163306661393332376130 +65346234343566613836306461613261623561313765663237353962663834396635393161626138 +65663731663162623062633436303238626631326632613339343335353036313231626331373538 +32393062363665666131646337613231383934323132326332396338396361323832353263623938 +66393635323836656365663866616637613335646163353065626538386639393365373366363163 +65643266363537313237373765366665643863363239383330646233366333363462396233393733 +31376464623436623165316365613665643236316136633337663762323363386163396364636332 +30343065623238313139343839653633316664313634636535666435366230333961343163613839 +61646666313136613734663238306563633837613134376362633966353233636433363166383363 +31363962636633616433646236626132633534663430653631356538336139613430653366353061 +33383634316137323132396336383062633866616639366633616363393161656361363834326435 +33373561396466383638613665376137653738616461333236323463313264643334313662363337 +61663434303464633163353366323965643865623931383565623165343565393665396239386533 +34353431313561336630663963363933666639636237323033343566626132386138363433346435 +32353761313765616230383639633061386161343363333938646163363732346337393930363761 +61396237633065366135386263613463663633303734313438383965613964316232633265636631 +65623236323930353665313165653764393263613339666634353364303165346432313739646537 +62333632383139666436313135653130643562643936323336626361336364313764346263316231 +30613730356133333762356631383032366538393139643337303963646630643934333431303234 +63636536633763616434623432646137376639616535313535373835363933613265363236346438 +62393331653435333539623461343239393230653462333463633538393063343139343564626234 +64323337336366643362613563333835353839386333613361383937633166333633333763646133 +35353031303734313161396430646137653636363631646465663739316334663339643832373836 +36316131356366633834393130393834643138663361366562313139313862393464306462336165 +34623335303831323336366265393938313738303837653435633735613139383738386561386639 +66633333373466313063643063623332383566656366336531326632396162333835653865663934 +33306139633462613661323861363563393334653662376565616437636436653263316536303532 +33663339636561646135383962666237666630663130623665653864383436356462613466393034 +64623033653966666533323465346230313662613237343035303033616263383165633865633535 +35366334376335313831303030336637636462656534353830623431363536643361663366656361 +31623162373161383866623465306162346534336435393639623536316662346531386434326537 +64383931663034656633636563386561396164636232363037316230393132303237333132383339 +66303665353839626462396132366666356339666238626132663531323236346532363866623530 +64386561646661336162656264346539343866343763616439306436636635663264613237366462 +66343337383265343832393139633562323738313232333762313131373636306234303266316435 +62663433323166386532643337666262656430663530643564303334393732653666656138303232 +38363835333137643537666561653030626633666263336661326437636464363261343938373335 +65346237323231653338366235393831653237393634633064353133323539306263336430373061 +66663134363931663263303031383736353135613839333638643435386234663334376366663139 +36663432653036666430313333343639316430613036393338326338373862653931383338376339 +62656236613764326636623238663030613864386633656337373064626632323733333164383238 +62363462336366396632626237663033383533313832353161393238336131353566323566396339 +62376566326535376532306632623531643138313334343165356665353631363033303730613935 +30633032343134353937653638373130343237613632303238333065663135633661383865336632 +31393138353535376538326466656132373666326332336364356530613862653562303765333832 +31386565393538656236626263356436393437353133663032613139333261373239356465353432 +33643635346334393136346236396636343861316364616465366339356637623061383830313863 +33333230643435356334376634363931653933666262383464643861373539326439396438333132 +62363166346664326264633163363134636331643130336232313565666664363062653863323165 +35396333396561316233353839643332633639303939663033386563313831366238666136393464 +61623662373638656336623962336461626161363261613935643965333938616265396635323433 +34323431333837323163313730323537653135663633333366376238643930663863636262303838 +38663034653339366237303830336537353137333866393033383463323931373135633538303234 +39353664623839386633636430636565333631633531383362396131336534376664326139326535 +38613434373737636464663737313430323536393737393262653866656463336561386566646133 +61393239636633616332643336383438396536383932633266303361393066393830663237393137 +66316437653865393561633862633061643635306334613432633839633332356638356461383961 +31376531373866303231313463653661656636623235613639666439323661316230313937333038 +36333362353638383332343438363330333263666566356263336639626332313363346539393362 +61333136396136313737633234353466383933376537346365393665633739636439313430323037 +62666331613034346137333334376165613162623432346461646561613233393235363631656431 +37666632643837353238306235613766613131333239316434656237663965616431383761653966 +36346130633765306336393033326135323336326530396635333264306535353965353031306662 +34663766373935653464353561636430626538653464363030653335613231643733303831646437 +65396136306330663432613932623932383566346636643932393036613030636139323730376639 +30663132323431396339663963666566383765393935616335393030366332313665383035646631 +37313166396636363464333763316235613562363164643133303930616632366434656531633536 +65376430313631373934316330316234666336613263643133323632653761623035343966356165 +32323231646537366565623963373630353735343463663361373837306261373337656363633166 +64393930326431613433316232343461363530663761666166376665656130643665633238396264 +32643933353666383365323262623733353033653766623734353837333430333664306662636434 +34623635353536333539373032323835383638393033316661366661316565396161666334323830 +31353631313165393230353438623132323339303664373264666464656336633966313539636564 +37616636646334663133376130663731653461373664343966306637346632386262656133663432 +37353062633434643063623136356364623833336336666235366366656666366232623136383739 +37626436643562646430633564396439323730623563616366303137653765666533306331643331 +66633934386430383631623166386539313035326632386639646261643236366333663539643330 +30613535666238623137626236313038656335353863623031366466303934616438336135656433 +36653966333236326636663763393766643265366164303930326361313265326430333766366139 +64356138666230303263383061376138613938353039313163646662336435313966316239313662 +31353334303532646164313634316666663562613037373564646566646136633638326333613834 +64383131356433653837353132623263313330376338613836633365353965383965666239313066 +62623462376566613039343235653635353064393861326134653535373932623962376339613637 +30646461646230333330623832356166653866633731306465663566653733363630653037643638 +64326462663830653335663932616665313064333333626433616637656662663834653935393531 +31313062326639393231303064636262386361643635353737383261333035646638383030343963 +62393963346464383966663766363262396636656163633638306361373166633762613963666339 +37353130666463653634333233633334666364623834313532363237396233613834653237653365 +62356432633539363530393131323865366464383465623065333637613733313935663661393665 +33313364643833336131353962373361363162373863356463316132356135316561313564383636 +65316364636666333063666232363164656139623636636661646433613964656631346438366163 +30343931633234633137616235303563643039663035623334316631376533323132623334376135 +33353137313534323335333464306336626139373532356536323630393066303633373836326636 +63636263343061366233323134356131316232616162313361656639306332313438316436353236 +65643239333730666633313962386236393663393537613435333935336331353664386538346139 +39616532653239656135393535306261656563386331313734633633333161326333353331613637 +66656662393830343435303462393865386337353539346663303535633738336639396337336466 +65383661626462653037326636356537313039313066613862386462643634326331326236366631 +31303238613531393766363165306534383037623534323232313463343766336661383637616538 +38343864386532303736316638663038636332633264353464393662336532353635643165633533 +63373632653066613133653962356439663966326333623332333737323934346139346330343634 +63613130376533656633356532613963386666306435366237643135613937633032656431353833 +31393033656531643761313431623638383038356233643531343466613637376661343463633437 +63336233623034303038343636333566306331343966393865643234613233316539313762396161 +34316638383163366435643535633834613930393432616464336434363230353964646433613433 +31623064393733393065653662613334313239366333323438396365666335666666306363396133 +35356131666132336134386237666633653231636361633930663065346666656137376661613137 +66333564653232303266386435333734316535333162323338323265363439373935666138666438 +30623161353134353964373334383530613663643061323864363662393035336136666135646330 +63363737643538643935613962643866663936323264333864393764376130386233663334366431 +38356438623238313966623130626139313664623139656166366334326238333031363539363037 +36313930633037353835326635376164633239643737326161646634653933333239313637626662 +61313762346539383036336330313665623337356639326237376330613465653736396138316466 +36326538313161663935306166653864386637613432316266633534396365336338303939346536 +31623664353935333930366236666634363133316438633439336637376366366331373339653835 +31343637643838656465343037613561643063323563653263636532386633303966316364343461 +32656464383661666335323037656436373132306566366262353037353438396337316364313666 +66363030306465616164343035376337636431636339663531333239663864316465373332373534 +65313462376535333661343931623966336435633730313035353631383436333162623030373061 +31383239333164363538356430373934356161633634613432623834396562616134643665373064 +39656364303962363035333835616463636331666336616335383035626538663266633330363231 +34636630373534613033616165383935343436386661626161633336366265333738376663333233 +38623438376434306133323365636635643234616533333063323565313036313739626464643535 +38333662646635373337396666376638346337346536656263656663333266653932323936336633 +64643366386161323037653335663533613066313862333630653530323765646233643861653837 +61656231333039633463653762343463366334623137663032613861646539343732376264336139 +38366138383762383531386336333463663839333064623765306363356536323362346433343665 +64616261653933376561393632316139313534376233313036313963613534623539353232376534 +66646362316364373334323533326433383230326332343765623566653035336266383634353238 +66353164623565306230353834396434633233396335333930353237633663353862346437343436 +37383666666263646538616665646264643535333532376662396538393062393238376263326235 +30323437623261356565636466313032343135346166663934656537663837383639323638323937 +38323562323565306336636131313430656231376339666535633035363861373639633535343533 +39313563353863663439616132316136393231353266396638643761653363653564376335646365 +34393338323462356363613661313536333233653965323434336361633730346666393034613966 +30353437323366653738376461346531316137376164616164363766386131313332323535656236 +39633038303636393536363938643638383037383130663263313832653064396330316134613736 +32316663393832373133306435616364656633646565326661633535396634643861323831633661 +65303737663731653066343531336330633732376563303163653065326663366264303537646238 +34663833363538646236646263383634366133376365336638633962343864393131326565363333 +39666636626461346632643361643862323233613963323266623434303338383366656436653832 +35633865663062386437336665323566616538623265323365616666373062306331643835316564 +61643962373131366432616562323463383534376534636132653761663232613765353132313964 +33356634636335373837396530663830613331383235323965356165356235623036303631376139 +32313532636433653433646662633664383666633566313335613530346564353161376536646466 +62353533366434366534353261383363633762653532333431383930323637623736613637653930 +33623037373439623736356264346562383533323330323164633638343364383035376463633831 +38626634393937356534653237303835336666623338646361313333303462653661623133356236 +37636133363863633765396561363163343365613030633638393630653165323861333337313231 +6536633566373865643733383466646439383065636532336431