summaryrefslogtreecommitdiff
path: root/doc/markdown/automation-stack-architecture.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/markdown/automation-stack-architecture.md')
-rw-r--r--doc/markdown/automation-stack-architecture.md767
1 files changed, 767 insertions, 0 deletions
diff --git a/doc/markdown/automation-stack-architecture.md b/doc/markdown/automation-stack-architecture.md
new file mode 100644
index 0000000..2ae775c
--- /dev/null
+++ b/doc/markdown/automation-stack-architecture.md
@@ -0,0 +1,767 @@
+# Far-Edge Automation Stack Deployment Guide
+
+The Far-Edge automation stack consists of nine Ubuntu 18.04 hosts:
+
+- Two load balancers
+- Two middleware application hosts
+- Two ansible hosts
+- Three database hosts
+
+The provisioning of these hosts in openstack is outside the scope of
+this document. There will be a separate document to address this.
+
+There is an additional host in the production stack to handle LDAP
+dual-stack proxying to reach USWIN. This host does not live in the
+automation stack tenant space. It is a standalone VM managed by VCPe.
+
+## OpenStack tenant space
+
+In both production and MTCE the far-edge automation stack runs in an
+OpenStack tenant space. (Production runs in VCPe.) Creating the
+OpenStack objects (neutron networks, cinder volumes, instances) is
+beyond the scope of this document and will be documented separately.
+
+Secgroup rules must be created to allow network traffic. Use a script
+like the following to create the secgroup rules:
+
+ #!/bin/bash
+
+ private_network_cidr="2001:4888:a21:3102:245:29::/112"
+ public_network_cidrs="2001:4888::/32"
+
+ for name in default-grp; do
+ openstack security group show ${name} || openstack security group create --description "${name}" ${name}
+ for protocol in tcp udp; do
+ if [ "openstack security group show ${name} -f shell -c rules | grep -F 'ingress' | grep -F \"port_range_min='1'\" | grep -F \"port_range_max='65535'\" | grep -F \"${protocol}\" | grep -F 'IPv6'" == "" ]; then
+ openstack security group rule create --egress --protocol ${protocol} --src-ip ::/0 --dst-port 1:65535 --ethertype IPv6 ${name}
+ fi
+ done
+ for cidr in ${private_network_cidr} ${public_network_cidrs}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"icmp\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol icmp --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ for port in 22; do
+ for cidr in ${private_network_cidr} ${public_network_cidrs}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"port_range_min='${port}'\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol tcp --dst-port ${port} --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ done
+ done
+
+ for name in icinga; do
+ openstack security group show ${name} || openstack security group create --description "${name}" ${name}
+ for port in 5665; do
+ for cidr in ${private_network_cidr}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"port_range_min='${port}'\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol tcp --dst-port ${port} --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ done
+ done
+
+ for name in ldap; do
+ openstack security group show ${name} || openstack security group create --description "${name}" ${name}
+ for port in 636; do
+ for cidr in ${private_network_cidr}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"port_range_min='${port}'\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol tcp --dst-port ${port} --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ done
+ done
+
+ for name in web; do
+ openstack security group show ${name} || openstack security group create --description "${name}" ${name}
+ for port in 443 3000; do
+ for cidr in ${private_network_cidr} ${public_network_cidrs}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"port_range_min='${port}'\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol tcp --dst-port ${port} --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ done
+ for port in 80 3000 3080 3128:3130 8000; do
+ for cidr in ${private_network_cidr}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"port_range_min='${port}'\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol tcp --dst-port ${port} --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ done
+ done
+
+ for name in galera; do
+ openstack security group show ${name} || openstack security group create --description "${name}" ${name}
+ for port in 3306 4444 4567 9200 13306; do
+ for cidr in ${private_network_cidr}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"port_range_min='${port}'\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol tcp --dst-port ${port} --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ done
+ done
+
+ for name in zmq; do
+ openstack security group show ${name} || openstack security group create --description "${name}" ${name}
+ for port in 5555:5559; do
+ for cidr in ${private_network_cidr}; do
+ if [ "$(openstack security group show ${name} -f shell -c rules | grep -F \"port_range_min='${port}'\" | grep -F \"remote_ip_prefix='${cidr}'\")" == "" ]; then
+ openstack security group rule create --ingress --protocol tcp --dst-port ${port} --src-ip ${cidr} --ethertype IPv6 ${name}
+ fi
+ done
+ done
+ done
+
+ exit 0
+
+## Database
+
+```far_edge_ops_api``` and icinga2 require a database backend. We
+currently use postgresql. The goal is to migrate to
+galera/mariadb. For now we are using only one database host, but when
+we switch to galera we will use all three. The galera solution is
+dockerized. It is a mature and well-tested product of the VCP Metering
+project.
+
+### Installation
+
+Install postgresql on the first database host per the typical
+procedure that can be found on the internet. TODO: provide a link to
+an internet HOWTO that best fits our needs.
+
+#### postgresql.conf:
+
+ data_directory = '/var/lib/postgresql/12/data'
+ listen_addresses = '*'
+ port = 5432
+ max_connections = 2000
+ password_encryption = md5
+ ssl = off
+ shared_buffers = 2000MB
+ work_mem = 4MB
+ maintenance_work_mem = 256MB
+ dynamic_shared_memory_type = posix
+ wal_buffers = 2MB
+ checkpoint_timeout = 15min
+ max_wal_size = 1GB
+ min_wal_size = 80MB
+ checkpoint_completion_target = 0.9
+ logging_collector = on
+ log_directory = '/var/lib/postgresql/12_log/'
+ log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
+ log_rotation_size = 50MB
+ log_min_duration_statement = 5
+ log_checkpoints = on
+ log_connections = on
+ log_disconnections = on
+ log_duration = on
+ log_error_verbosity = default
+ log_line_prefix = '%m, %d, %a. %r, %s, %x, %p '
+ log_timezone = 'GMT'
+ autovacuum = on
+ idle_in_transaction_session_timeout = 43200000
+ datestyle = 'iso, dmy'
+ timezone = 'GMT'
+ lc_messages = 'en_US.utf8'
+ lc_monetary = 'en_US.utf8'
+ lc_numeric = 'en_US.utf8'
+ lc_time = 'en_US.utf8'
+ default_text_search_config = 'pg_catalog.simple'
+ plperl.on_init = 'use utf8; use re; package utf8; require "utf8_heavy.pl";'
+
+#### pg_hba.conf:
+
+ local icinga icinga md5
+ local all all password
+ local replication postgres trust
+ host icinga icinga 127.0.0.1/32 md5
+ host icinga icinga ::1/128 md5
+ host all all 127.0.0.1/32 password
+ host all all ::1/128 password
+ host icinga icinga 2001:4888:a21:3102::/32 md5
+ host all all 2001:4888:a21:3102::/32 password
+
+#### sysctl.conf:
+
+Configure ```kernel.shmmax``` and ```kernel.shmall``` to be 25\% of
+available RAM. For example on a 16GB host:
+
+ kernel.shmmax=4199411712
+ kernel.shmall=4199411712
+
+### User and database creation
+
+As the postgres user:
+
+ # createuser -l -P -e faredge
+ # createdb -e -O faredge faredge
+
+We do not need to populate the database with a schema. Django will do
+this automatically.
+
+## Load Balancers
+
+The services which run on the loadbalancer hosts are as follows:
+
+- apache
+- haproxy
+- icinga2
+
+### Apache
+
+#### SSL Certificates:
+
+A prerequisite for configuring apache is an SSL x509 certificate that
+answers to the following names:
+
+ middleware.<fqdn>
+ icinga.<fqdn>
+ dns-admin.<fqdn>
+
+Place the certificate in ```/etc/ssl/certs/``` and the key in
+```/etc/ssl/private```.
+
+#### Modules:
+
+Apache needs the following modules enabled:
+
+ - access_compat.load
+ - alias.conf
+ - alias.load
+ - auth_basic.load
+ - authn_core.load
+ - authn_file.load
+ - authz_host.load
+ - authz_user.load
+ - authz_core.load
+ - autoindex.conf
+ - autoindex.load
+ - deflate.conf
+ - deflate.load
+ - dir.conf
+ - dir.load
+ - env.load
+ - filter.load
+ - http2.load
+ - mime.conf
+ - mime.load
+ - mpm_prefork.conf
+ - mpm_prefork.load
+ - negotiation.conf
+ - negotiation.load
+ - php7.2.conf
+ - php7.2.load
+ - proxy.conf
+ - proxy.load
+ - proxy_http.load
+ - proxy_http2.load
+ - proxy_wstunnel.load
+ - reqtimeout.conf
+ - reqtimeout.load
+ - rewrite.load
+ - setenvif.conf
+ - setenvif.load
+ - socache_shmcb.load
+ - ssl.conf
+ - ssl.load
+ - status.conf
+ - status.load
+
+#### VirtualHosts:
+
+Apache needs the following sites enabled:
+
+ - dns-admin.conf
+ - far_edge_ops_api.conf
+ - icinga.conf
+ - webdav.conf
+
+```webdav.conf``` is only needed when an external HTTP share is not
+available.
+
+##### dns-admin.conf:
+
+ <VirtualHost [2607:f160:b:10f1::e]:443>
+ ServerName dns-admin.faredge.vzwops.com
+ ServerAdmin carlos.konstanski@verizonwireless.com
+ Protocols http/1.1
+ SSLEngine on
+ SSLProxyEngine on
+ SSLCertificateFile /etc/ssl/certs/vcpfe-lb-vip.faredge.vzwops.com.pem
+ SSLCertificateKeyFile /etc/ssl/private/vcpfe-lb-vip.faredge.vzwops.com.key
+ 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
+ SSLCompression off
+ SSLOptions +StrictRequire
+ ProxyPass "/" "http://[::1]:13000/"
+ ProxyPassReverse "/" "http://[::1]:13000/"
+ SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
+ ErrorLog "/var/log/apache2/dnsadmin_error_log"
+ CustomLog "/var/log/apache2/dnsadmin_access_log" common
+ </VirtualHost>
+
+##### far\_edge\_ops\_api.conf:
+
+ <VirtualHost [2607:f160:b:10f1::e]:443>
+ ServerName middleware.faredge.vzwops.com
+ ServerAdmin carlos.konstanski@verizonwireless.com
+ Protocols http/1.1
+ SSLEngine on
+ SSLProxyEngine on
+ SSLCertificateFile /etc/ssl/certs/vcpfe-lb-vip.faredge.vzwops.com.pem
+ SSLCertificateKeyFile /etc/ssl/private/vcpfe-lb-vip.faredge.vzwops.com.key
+ 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
+ SSLCompression off
+ SSLOptions +StrictRequire
+ ProxyPass "/" "http://[::1]:13080/"
+ ProxyPassReverse "/" "http://[::1]:13080/"
+ ErrorLog "/var/log/apache2/middleware_error_log"
+ CustomLog "/var/log/apache2/middleware_access_log" common
+ </VirtualHost>
+
+##### icinga.conf:
+
+ <VirtualHost [2607:f160:b:10f1::e]:443>
+ ServerName icinga.faredge.vzwops.com
+ ServerAdmin carlos.konstanski@verizonwireless.com
+ DocumentRoot "/usr/share/icingaweb2/public"
+ SSLEngine on
+ SSLProxyEngine on
+ SSLCertificateFile /etc/ssl/certs/vcpfe-lb-vip.faredge.vzwops.com.pem
+ SSLCertificateKeyFile /etc/ssl/private/vcpfe-lb-vip.faredge.vzwops.com.key
+ 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
+ SSLCompression off
+ SSLOptions +StrictRequire
+
+ <Directory "/usr/share/icingaweb2/public">
+ Options SymLinksIfOwnerMatch
+ AllowOverride None
+
+ <IfModule mod_authz_core.c>
+ <RequireAll>
+ Require all granted
+ </RequireAll>
+ </IfModule>
+
+ SetEnv ICINGAWEB_CONFIGDIR "/etc/icingaweb2"
+ EnableSendfile Off
+
+ <IfModule mod_rewrite.c>
+ RewriteEngine on
+ RewriteBase /
+ RewriteCond %{REQUEST_FILENAME} -s [OR]
+ RewriteCond %{REQUEST_FILENAME} -l [OR]
+ RewriteCond %{REQUEST_FILENAME} -d
+ RewriteRule ^.*$ - [NC,L]
+ RewriteRule ^.*$ index.php [NC,L]
+ </IfModule>
+ </Directory>
+ </VirtualHost>
+
+##### webdav.conf:
+
+ <VirtualHost *:80>
+ ServerName webdav.faredge.vzwops.com
+ ServerAdmin carlos.konstanski@verizonwireless.com
+ DocumentRoot "/var/www/html/webdav"
+ SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
+ ErrorLog "/var/log/apache2/webdav_error_log"
+ CustomLog "/var/log/apache2/webdav_access_log" common
+ <Directory "/var/www/html/webdav">
+ AllowOverride limit
+ Options Indexes FollowSymLinks
+ </Directory>
+ </VirtualHost>
+
+##### Webdav directory:
+
+Create this directory only if you don't have access to an external HTTP share and you are using the webdav VirtualHost above:
+
+ - /var/www/html/webdav
+
+### HAProxy
+
+Use the following haproxy config, adjusting IP addresses, hostnames and credentials as needed:
+
+ global
+ tune.ssl.default-dh-param 2048
+ log /dev/log local0
+ log /dev/log local1 notice
+ chroot /var/lib/haproxy
+ stats socket /run/haproxy/admin.sock mode 660 level admin
+ stats timeout 30s
+ maxconn 5000
+ user haproxy
+ group haproxy
+ daemon
+ ca-base /etc/ssl/certs
+ crt-base /etc/ssl/private
+ ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
+ ssl-default-bind-options no-sslv3
+
+ defaults
+ log global
+ option dontlognull
+ timeout connect 10s
+ timeout client 60s
+ timeout server 180s
+ errorfile 400 /etc/haproxy/errors/400.http
+ errorfile 403 /etc/haproxy/errors/403.http
+ errorfile 408 /etc/haproxy/errors/408.http
+ errorfile 500 /etc/haproxy/errors/500.http
+ errorfile 502 /etc/haproxy/errors/502.http
+ errorfile 503 /etc/haproxy/errors/503.http
+ errorfile 504 /etc/haproxy/errors/504.http
+
+ listen stats
+ bind 127.0.0.1:1993
+ mode http
+ option httplog
+ option forwardfor
+ stats enable
+ stats uri /stats
+ stats auth someuser:somepass
+ stats refresh 30s
+ stats show-node
+ stats hide-version
+ log global
+
+ frontend dns-admin
+ bind 0.0.0.0:13000
+ bind :::13000
+ mode http
+ option httplog
+ option forwardfor
+ default_backend dns-admin-backend
+
+ backend dns-admin-backend
+ balance roundrobin
+ mode http
+ option log-health-checks
+ option httpchk GET /dns HTTP/1.1\r\nHost:\ dns-admin.faredge.vzwops.com\r\nUser-Agent:\ curl/7.35.0\r\nAccept:\ */*\r\nAuthorization:\ Basic\ b3BlbmJvb2s6WnlsejNmZE1TZDhTVmlod0w5TnlaTHpU
+ default-server inter 10s fall 1 rise 1
+ server server-1 [2607:f160:b:10f1::7]:80 check
+ #server server-2 [2607:f160:b:10f1::8]:80 check
+
+ frontend far_edge_ops_api
+ bind 0.0.0.0:13080
+ bind :::13080
+ mode http
+ option httplog
+ option forwardfor
+ reqdel ^Host:
+ reqadd Host:\ middleware.faredge.vzwops.com
+ default_backend far_edge_ops_api-backend
+
+ backend far_edge_ops_api-backend
+ balance roundrobin
+ mode http
+ option log-health-checks
+ option httpchk GET /caas/ HTTP/1.1\r\nHost:\ middleware.faredge.vzwops.com\r\nUser-Agent:\ curl/7.35.0\r\nAccept:\ */*\r\nAuthorization:\ Basic\ bWlkZGxld2FyZXVzZXI6bWlkZGxld2FyZXBhc3N3b3Jk
+ default-server inter 10s fall 1 rise 1
+ server server-1 [2607:f160:b:10f1::6]:3080 check
+ #server server-2 [2607:f160:b:10f1::5]:3080 check
+
+We currently only proxy to one backend for both ```dns-admin``` and
+```far_edge_ops_api``` because there has been no opportunity to test
+the behavior of the apps in a multiple-backend configuration. This is
+why ```server-2``` is commented out. TODO: update this document when
+this testing is complete.
+
+### Icinga2
+
+The icinga2 configuration is mostly standard. TODO: provide a link to
+an internet HOWTO from which the rest of this documentation can
+build. There will be only minor additions to the standard base
+install.
+
+## Jenkins
+
+The applications are built and deployed from jenkins. The build jobs
+already exist. But a new deploy job needs to be added for the new
+environment which you are building.
+
+### env.yaml
+
+All of the far-edge builds and deploymenets are run on the jenkins
+slave ```openbook-docker-slave-4.meter.vzwops.com```. Log onto this
+host and edit three files in the jenkins home directory
+```/var/lib/jenkins/```:
+
+ - env.yaml.ansible-queue
+ - env.yaml.dns-admin
+ - env.yaml.far-edge-ops-api
+
+A new deployment target section needs to be added to each of these
+files. Give the environment a new unique name and use the same name in
+all three files.
+
+### jenkins-job-builder (jjb)
+
+Clone the following git repo onto your laptop:
+
+ git@gitlab.verizon.com:ONV6661_VCPSPUBLIC/jjb.git
+
+Create an ini file called ```verizoncloudplatform.com.ini``` in the
+top-level directory of your jjb git checkout with the following
+contents:
+
+#### verizoncloudplatform.com.ini:
+ [job_builder]
+ ignore_cache=True
+ keep_descriptions=False
+ include_path=.:scripts:~/git/
+ recursive=False
+ exclude=.*:manual:./development
+ allow_duplicates=False
+
+ [jenkins]
+ user=<your_jenkins_username>
+ password=<your_jenkins_api_token>
+ url=https://openbook-jenkins-master.meter.vzwops.com:8080/
+ timeout=120
+ query_plugins_info=False
+
+Follow these steps to create the new deploy jobs:
+
+- Open the file ```yaml/verizoncloudplatform.com/deploy-vcpfe.yaml```
+ in an editor.
+
+- Add three new jobs to the list, one for each app
+ (```ansible-queue```, ```dns-admin``` and
+ ```far-edge-ops-api```). Set the target attribute to the new ansible
+ target which you created in env.yaml in the previous section.
+
+- ```# ./run.sh verizoncloudplatform.com```
+
+Once this is done, log into the jenkins UI to verify that the new jobs
+were created.
+
+Push your jjb changes to git. (The ini file is gitignored; it is your
+private file.)
+
+## Application hosts
+
+The services which run on the application hosts are as follows:
+
+ - far_edge_ops_api
+
+### far\_edge\_ops\_api
+
+The middleware (as ```far_edge_ops_api``` is ubiquitously known) is a
+docker containerized django web application.
+
+#### Build/deploy
+
+The application can be built and deployed from jenkins:
+
+https://openbook-jenkins-master.meter.vzwops.com:8080
+
+Run the job ```docker-container-far-edge-ops-api``` to build the
+docker container, and the appropriate
+```far-edge-ops-api-deploy-vcpfe-<env>``` job to deploy it to an
+environment.
+
+#### Configure
+
+It might seem backwards to perform the build and deployment before
+configuring. It's a chicken-and-egg problem: the deployment needs to
+create the required files and directories before configuration can
+commence. For first-time deployments the process will look like: build
+-> deploy -> configure -> deploy. This is true of all three
+applications.
+
+The main configuration directory is ```/etc/far-edge-ops-api/```. It
+looks like the following on a working system:
+
+ $ tree /etc/far-edge-ops-api/
+ /etc/far-edge-ops-api/
+ ├── modules.d
+ │   ├── wsgi.conf
+ │   └── wsgi.load
+ ├── settings.py
+ └── vhosts.d
+ └── far-edge-ops-api.conf
+
+```settings.py``` is a rather long file, too long to include here. Get
+a copy from a known good source (a production or lab server) and edit
+to suit the new environment.
+
+```far-edge-ops-api.conf``` is a rather typical-looking apache
+VirtualHosts file, but with LDAP auth added. First the file:
+
+##### far-edge-ops-api.conf:
+
+ LDAPTrustedGlobalCert CA_BASE64 "/etc/apache2/auth/uswin_ca.pem"
+ LDAPTrustedGlobalCert CA_BASE64 "/etc/ssl/certs/selfsigned_root_cert.crt"
+ LDAPTrustedMode SSL
+ LDAPLibraryDebug 7
+
+ <VirtualHost *:3080>
+ ServerName middleware.<fqdn>
+ DocumentRoot "/opt/far-edge-ops-api/src/src"
+ WSGIScriptAlias / /opt/far-edge-ops-api/src/src/far_edge_ops_api/wsgi.py
+ WSGIDaemonProcess middleware.<fqdn> processes=20 threads=15 display-name=%{GROUP} python-home=/opt/far-edge-ops-api/src/venv
+ WSGIProcessGroup middleware.<fqdn>
+ Alias /static/ /opt/far-edge-ops-api/src/src/static/
+ TimeOut 600
+ SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
+ ErrorLog "/var/log/apache2/far-edge-ops-api_error_log"
+ CustomLog "/var/log/apache2/far-edge-ops-api_access_log" common
+ </VirtualHost>
+
+ <Directory "/opt/far-edge-ops-api/src/src">
+ AllowOverride all
+ Options FollowSymlinks
+ AuthName "USWIN"
+ AuthType Basic
+ AuthBasicProvider ldap
+ AuthLDAPURL "ldaps://vcpfe-ldap-prod.vcpfe.vzwops.com:636/DC=uswin,DC=ad,DC=vzwcorp,DC=com?sAMAccountName?sub?(objectclass=*)"
+ AuthLDAPBindDN "CN=SVC-VCP-LDAP,OU=SVC,OU=FNA,DC=uswin,DC=ad,DC=vzwcorp,DC=com"
+ AuthLDAPBindPassword "<password_for_SVC-VCP-LDAP_account>"
+ Require valid-user
+ </Directory>
+
+ <Directory "/opt/far-edge-ops-api/src/src/static">
+ AllowOverride limit
+ Require all granted
+ Options Indexes FollowSymLinks
+ </Directory>
+
+There are two SSL certs because the far-edge stack is IPv6-only while
+the production LDAP endpoint (USWIN) is IPv4-only. So we must use a
+proxy. The first cert is the actual uswin cert, while the second cert
+is the one for the proxy. Both of these certs must be placed on the
+app hosts.
+
+Replace ```<fqdn>``` with the DNS domain. Replace
+```<password_for_SVC-VCP-LDAP_account>``` with the correct password.
+
+OpenLDAP needs to be configured with these same certs. Since they are
+self-signed, openldap will reject them unless they are listed as
+exceptions.
+
+#### /etc/ldap/ldap.conf:
+
+ TLS_CACERT /etc/apache2/auth/uswin_ca.pem
+ LDAPTLS_CACERT /etc/ssl/certs/self_ca_signed_cert_and_key_2.pem
+
+Now that the configuration is complete, rerun the deployment from
+jenkins. This time the application should start normally.
+
+## Queue hosts
+
+The services which run on the application hosts are as follows:
+
+ - ansible-queue
+ - dns-admin
+
+### ansible-queue
+
+```ansible-queue``` is a docker containerized common lisp
+application.
+
+#### Build/deploy
+
+The application can be built and deployed from jenkins:
+
+https://openbook-jenkins-master.meter.vzwops.com:8080
+
+Run the job ```docker-container-ansible-queue``` to build the docker
+container, and the appropriate ```ansible-queue-deploy-vcpfe-<env>```
+job to deploy it to an environment.
+
+#### Configure
+
+Two files are required in the directory ```/etc/ansible-queue/```:
+
+ - .ansible_pass.far_edge
+ - options.lisp
+
+```.ansible_pass.far_edge``` is the ansible vault password
+file. Obtain a copy from an existing queue host.
+
+```options.lisp``` is the config file for the ```ansible-queue```
+application.
+
+##### options.lisp:
+
+ ((:queue (:num-icinga-process-threads 1
+ :num-bmc-process-threads 30
+ :num-nic-process-threads 20
+ :num-wr-process-threads 25
+ :num-dns-process-threads 1
+ :num-patch-process-threads 1
+ :num-hw-process-threads 20
+ :num-fix-process-threads 20
+ :icinga-wait-interval 0
+ :bmc-wait-interval 1
+ :nic-wait-interval 30
+ :wr-wait-interval 0
+ :dns-wait-interval 0
+ :patch-wait-interval 30
+ :hw-wait-interval 1
+ :fix-wait-interval 1
+ :sleep-interval 60
+ :ipv6 t
+ :vault-password-file "/etc/ansible-queue/.ansible_pass.far_edge"
+ :icinga-queue-url "tcp://*:5555"
+ :bmc-queue-url "tcp://*:5556"
+ :nic-queue-url "tcp://*:5557"
+ :wr-queue-url "tcp://*:5558"
+ :dns-queue-url "tcp://*:5559"
+ :patch-queue-url "tcp://*:5560"
+ :hw-queue-url "tcp://*:5561"
+ :fix-queue-url "tcp://*:5562"
+ :middleware-url "https://middleware.vcpfe.vzwops.com"
+ :middleware-username "SVC-Far-Edge"
+ :middleware-password "<password_for_SVC-Far-Edge_account>")))
+
+Replace ```<password_for_SVC-Far-Edge_account>``` with the correct
+password.
+
+Now that the configuration is complete, rerun the deployment from
+jenkins. This time the application should start normally.
+
+### dns-admin
+
+```dns-admin``` is a docker containerized web application written in
+common lisp and clojurescript.
+
+#### Build/deploy
+
+The application can be built and deployed from jenkins:
+
+https://openbook-jenkins-master.meter.vzwops.com:8080
+
+Run the job ```docker-container-dns-admin``` to build the docker
+container, and the appropriate ```dns-admin-deploy-vcpfe-<env>``` job
+to deploy it to an environment.
+
+#### Configure
+
+Only one new config file is required. Use the following content
+verbatim:
+
+##### /etc/dns-admin/conf.lisp:
+
+ (:name "dns-admin"
+ :document-root "dns-admin"
+ :title "DNS Administration"
+ :meta-description "A website for administering DNS. Supports nsupdate and infoblox."
+ :dns (:label "CDS Infoblox"
+ :backend-type "infoblox"
+ :url "https://infoblox.alias/wapi/v2.6"))
+
+Notice the odd-looking hostname ```infoblox.alias```. The following
+needs to be added to ```/etc/hosts```:
+
+ 2607:f160:8a02:8016:a0:103:0:10 infoblox.alias
+
+Now that the configuration is complete, rerun the deployment from
+jenkins. This time the application should start normally.