├── .gitignore ├── HowTo.md ├── LICENSE ├── README.md ├── SCREENSHOTS.md ├── build-server.sh ├── callback └── dashr_callback.py ├── config └── js │ └── main.data.js ├── dashr.go ├── dummy-ansible-files ├── ansible.cfg ├── group_vars │ ├── all │ └── env.alpha ├── host_vars │ ├── db1.alpha.example.com │ └── db2.alpha.example.com ├── inventories │ ├── env.alpha │ ├── env.beta │ └── env.local ├── logs │ ├── dashr_log_hostlist.yaml │ └── hosts │ │ └── 127.0.0.1 ├── pb01.yml ├── pb02.yml ├── pb03.yml ├── pb04.yml ├── pb05.yml ├── roles │ ├── bind │ │ ├── README.md │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ ├── masters │ │ │ │ └── db.example.com │ │ │ └── named.conf │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── role.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ ├── named.conf.local.master.j2 │ │ │ ├── named.conf.local.slave.j2 │ │ │ └── named.conf.options.j2 │ │ └── vars │ │ │ └── main.yml │ ├── memcached │ │ ├── README.md │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ ├── memcached_debian.j2 │ │ │ └── memcached_redhat.j2 │ │ └── vars │ │ │ └── main.yml │ ├── mysql │ │ ├── README.md │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ ├── .my.cnf.j2 │ │ │ ├── my.cnf.Debian.j2 │ │ │ └── my.cnf.RedHat.j2 │ │ └── vars │ │ │ ├── Debian.yml │ │ │ ├── RedHat.yml │ │ │ └── main.yml │ ├── nginx │ │ ├── README.md │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ └── epel.repo │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ ├── default.conf.j2 │ │ │ ├── default.j2 │ │ │ ├── nginx.conf.j2 │ │ │ └── site.j2 │ │ └── vars │ │ │ └── main.yml │ ├── ntp │ │ ├── .gitignore │ │ ├── README.md │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ └── ntp.conf.j2 │ │ ├── tests │ │ │ └── role.yml │ │ └── vars │ │ │ ├── Debian.yml │ │ │ └── RedHat.yml │ └── redis │ │ ├── README.md │ │ ├── defaults │ │ └── main.yml │ │ ├── files │ │ ├── epel6.repo │ │ └── epel7.repo │ │ ├── handlers │ │ └── main.yml │ │ ├── meta │ │ └── main.yml │ │ ├── tasks │ │ └── main.yml │ │ ├── templates │ │ ├── redis.conf.j2 │ │ └── rsyslogd.conf.j2 │ │ └── vars │ │ ├── Debian.yml │ │ ├── RedHat.yml │ │ └── main.yml └── sample-playbook.yml ├── goansible └── log_analyzer.go ├── screenshots ├── dashboard.failed.png ├── dashboard.passed.png ├── dashboard.png ├── dashboard.searched.png ├── homepage.png ├── hosts.png ├── playbooks.png └── roles.png └── www-data ├── 404.html ├── css ├── bootstrap-responsive.css ├── bootstrap-responsive.min.css ├── bootstrap.css ├── bootstrap.min.css ├── docs.css └── main.css ├── dashboard.html ├── favicon.ico ├── hosts.html ├── humans.txt ├── img ├── glyphicons-halflings-white.png └── glyphicons-halflings.png ├── index.html ├── js ├── home.js ├── js-yaml.min.js ├── main.dashboard.js ├── main.hosts.js ├── main.js ├── main.playbook.parser.js ├── main.roles.parser.js ├── plugins.js └── vendor │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── highcharts.exporting.js │ ├── highcharts.js │ ├── jquery-3.7.1.min.js │ ├── jstree.min.js │ ├── list.min.js │ ├── list.pagination.js │ ├── modernizr-2.6.1-respond-1.1.0.min.js │ └── yaml.js ├── playbooks.html ├── robots.txt ├── roles.html └── runner.html /.gitignore: -------------------------------------------------------------------------------- 1 | *swn 2 | *swo 3 | *swp 4 | *~ 5 | *.tmp 6 | *.pyc 7 | temp/* 8 | .bundle 9 | .venv 10 | .goenv 11 | .config 12 | *.cfg 13 | *.lock 14 | *.sock 15 | dummy-ansible-files/logs/anisble.dummy.log 16 | www-data/dummy-ansible-files/logs/anisble.dummy.log 17 | dummy-ansible-files/callbacks/* 18 | dummy-ansible-files/logs/* 19 | pkg/** 20 | -------------------------------------------------------------------------------- /HowTo.md: -------------------------------------------------------------------------------- 1 | ## Ansible Dashr 2 | 3 | ### HowTo Use 4 | 5 | ##### Customize Dashr 6 | 7 | > To show details of your own Ansible setup than provided dummy-data, can update config at "/config/js/main.data.js". 8 | > The variables here are self-explainatory, but still 9 | 10 | For Dashboard: 11 | > You'll need to set an ENV Variable by name "DASHR_LOG_DIRECTORY" which in case not set, shall be considered as "/var/log/ansible". Make sure Ansible and dashr has access to that path. 12 | > It also requires you to copy "/callback/dashr_callback.py" to your Ansible callback directory. If new to Ansible Callbacks read [Ansible Doc for Callback](http://docs.ansible.com/developing_plugins.html#callbacks) and [@jpmens quick description](http://jpmens.net/2012/09/11/watching-ansible-at-work-callbacks/) on it. 13 | > * dashr_log_directory: shall be set based on path to DASHR_LOG_DIRECTORY as "{{ DASHR_LOG_DIRECTORY }}/hosts" 14 | > * dashr_log_hostlist: set it as "{{ DASHR_LOG_DIRECTORY }}/dashr_log_hostlist.yaml" 15 | 16 | For Hosts: 17 | > * inventories: list of names of all inventories to be included 18 | > * inventories_www_path: web-path for root of Inventory Files 19 | > * group_vars_www_path: web-path for root of Group Var Files 20 | > * host_vars_www_path: web-path for root of Host Var Files 21 | 22 | For Playbooks: 23 | > * playbooks: list of all the playbooks to be included 24 | > * playbooks_www_path: web-path for root of Playbook YAML Files 25 | 26 | For Roles: 27 | > * roles: list of all the roles to be included 28 | > * roles_www_path: web-path for root of Roles directories 29 | 30 | > We'll enable Dashr to be capable of extracting configuration from any provided Ansible-Setup path or provide Interactive Utility to feed in details. But that for sometime later when other prior features are there. 31 | 32 | --- 33 | 34 | ##### Start Dashr 35 | 36 | > ``` $ go run dashr.go ``` 37 | > requires [golang](https://golang.org/doc/install) 38 | 39 | > ``` $ go run dashr.go -h ``` 40 | > to view all optional parameters available to be configure when showing a custom Ansible setup (which is the aim) 41 | > Available parameters with there default values are: 42 | > * -ansible="dummy-ansible-files": path to ansible setup root of Playbooks, Roles Dir 43 | > * -config="config": path to fetch/save Config used by Static Site Content; from here it fetchs main.data.js 44 | > * -fqdn="127.0.0.1": IP/FQDN to run HTTP listener at 45 | > * -http="8001": port to run HTTP listener at 46 | > * -www="www-data": path to ansible dashr static site content, shouldn't normally change 47 | > 48 | > so, to run it at port:8888 and point to a custom ansible-setup:/home/you/ansibleX dir would change command to 49 | > ``` $ go run dashr.go -http="8888" -ansible="/home/you/ansibleX" ``` 50 | 51 | 52 | > currently dashr.go doesn't do much excpet serving static content, so anything can be run to serve content at root of repo like ```python -m SimpleHTTPServer ``` 53 | 54 | --- 55 | 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 AbhishekKr 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # W.I.P. 2 | * Version: 0.0.5 3 | 4 | ## Ansible Dashr 5 | 6 | ##### It's supposed to fill in basic Dashboard/Controller requirement of Ansible WebUI. 7 | 8 | > [Screenshots of fully/almost working features](./SCREENSHOTS.md) 9 | 10 | > [QuickStart Guide on HowTo use Ansible-Dashr](./HowTo.md) 11 | 12 | --- 13 | 14 | #### Features 15 | 16 | * Working 17 | > * **Dashboard**: provides last status updates of all Host's Playbook:Role:Tasks by use of ansible callback plugin 18 | > * **Playbook**: provides linked view to workflow of listed playbook 19 | > * **Hosts**: provides exploratory interface to all host/hostgroups under all listed inventories and their associated host/group-vars 20 | > * **Roles**: gives task level details for listed roles::main 21 | 22 | * InProgress 23 | > * **Dashr**: golang based HTTP service for all static content and task API (for Dashboard, Runner, etc) 24 | > * **HomePage**: provides quick view of all listed details and some-bits from Dashboars&Runner once they are completed 25 | 26 | * ToBeDone 27 | > * **OptOut**: Enable to opt-out of any feature, say you don't wanna use Callabck plug-in just for the Dashboard... so opt-out of using dashboard 28 | > * **Runner**: enables user to compose and run ansible tasks from listed details 29 | 30 | --- 31 | 32 | re-using [Ansible-UI](https://github.com/mavimo/ansible-ui) pieces for Presentation Layer which is a light template over Bootstrap 33 | 34 | -------------------------------------------------------------------------------- /SCREENSHOTS.md: -------------------------------------------------------------------------------- 1 | ## Ansible-Dashr 2 | 3 | #### Screenshots 4 | 5 | * **Homepage Graphs** 6 | 7 | ![Ansible-Dashr HomePage :(](/screenshots/homepage.png "Screenshot of Homepage with some insight graphs") 8 | --- 9 | 10 | * **Dashboard** 11 | 12 | ![Ansible-Dashr Dashboard Full View Missing :(](/screenshots/dashboard.png "Screenshot of Dashboard FullRun") 13 | ![Ansible-Dashr Dashboard Passed-Only View Missing :(](/screenshots/dashboard.passed.png "Screenshot of Dashboard PassedRun") 14 | ![Ansible-Dashr Dashboard Failed-Only View Missing :(](/screenshots/dashboard.failed.png "Screenshot of Dashboard FailedRun") 15 | ![Ansible-Dashr Dashboard Search View Missing :(](/screenshots/dashboard.searched.png "Screenshot of Dashboard Search") 16 | --- 17 | 18 | * **Hosts** 19 | 20 | ![Ansible-Dashr Hosts View Missing :(](/screenshots/hosts.png "Screenshot of Host") 21 | --- 22 | 23 | * **Roles** 24 | 25 | ![Ansible-Dashr Roles View Missing :(](/screenshots/roles.png "Screenshot of Host") 26 | --- 27 | 28 | * **Playbook** 29 | 30 | ![Ansible-Dashr Playbook View Missing :(](/screenshots/playbooks.png "Screenshot of Host") 31 | --- 32 | -------------------------------------------------------------------------------- /build-server.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | THISDIR=$(dirname $0) 4 | 5 | # BATCH 6 | # set GOARCH=amd64 7 | # set GOOS=linux 8 | # go tool dist install -v pkg/runtime 9 | # go install -v -a std 10 | # go build dashr.go 11 | 12 | export CGO_ENABLED=0 13 | export GOARCH=amd64 14 | export GOOS=linux 15 | mkdir -p $THISDIR/pkg 16 | go build -o $THISDIR/pkg/dashr $THISDIR/dashr.go 17 | -------------------------------------------------------------------------------- /callback/dashr_callback.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Author: [AbhishekKr ](http://abhishekkr.github.io) 5 | """ 6 | 7 | import os 8 | import sys 9 | import yaml 10 | 11 | 12 | EXTRA_DETAILS = ['cmd', 'command', 'start', 'end', 'delta', 'msg', 'stdout', 'stderr'] 13 | 14 | 15 | def stringify(something): 16 | return str(something).encode('ascii','ignore') 17 | 18 | 19 | def refresh_host_yaml(host_yaml, type={}): 20 | """ Prepares empty host yaml if not present. """ 21 | with open(host_yaml, "w") as f: 22 | yaml.dump(type, f) 23 | 24 | 25 | def state_to_yaml(host_yaml, _details): 26 | """ Update Host yaml log file states. """ 27 | 28 | if not os.path.exists(host_yaml): 29 | refresh_host_yaml(host_yaml) 30 | 31 | with open(host_yaml) as f: 32 | newdct = yaml.load(f) 33 | 34 | newdct[_details["name"]] = _details 35 | 36 | with open(host_yaml, "w") as f: 37 | yaml.dump(newdct, f) 38 | 39 | 40 | def get_host_yaml(host_log, log_dir, host): 41 | """ Update hostlog yaml with host name. Return path for host yaml to be log created. """ 42 | host = host.split("->")[0].strip() 43 | 44 | with open(host_log) as f: 45 | host_list = yaml.load(f) 46 | 47 | if host not in host_list: 48 | host_list.append(host) 49 | 50 | with open(host_log, "w") as f: 51 | yaml.dump(host_list, f) 52 | 53 | return os.path.join(log_dir.strip(), host) 54 | 55 | 56 | def prepare_details(obj, result, state): 57 | _details = {"state": state, "details": {}} 58 | if type(result) == type(dict()): 59 | return _details 60 | 61 | _module = result['invocation']['module_name'] 62 | 63 | if "role_name" in dir(obj.task): 64 | if obj.task.role_name: 65 | _module = "%s:%s" % (obj.task.role_name, _module) 66 | _details["details"]["role_name"] = obj.task.role_name 67 | else: 68 | _module = ":%s" % (_module) 69 | 70 | if "filename" in dir(obj.playbook): 71 | _playbook_filename = stringify(obj.playbook.filename) 72 | _playbook = ".".join(_playbook_filename.split('.')[0:-1]) 73 | _module = "%s:%s" % (_playbook, _module) 74 | _details["details"]["playbook_name"] = _playbook 75 | 76 | _details["name"] = stringify(_module) 77 | 78 | for field in EXTRA_DETAILS: 79 | if field in result.keys(): 80 | _details["details"][field] = stringify(result[field]) 81 | 82 | return _details 83 | 84 | 85 | def log_error(err_file, err_msg): 86 | """ make note of errors instead of failing ansible run cuz of callback""" 87 | with open(str(err_file), "a") as myfile: 88 | myfile.write(str(err_msg)) 89 | 90 | 91 | class CallbackModule(object): 92 | """ 93 | This plugin makes use of the following environment variables: 94 | DASHR_LOG_DIRECTORY (else uses /var/log/ansible to create dashr logs) 95 | """ 96 | 97 | def __init__(self): 98 | try: 99 | self.dashr_log_directory = os.getenv('DASHR_LOG_DIRECTORY', '/var/log/ansible') 100 | 101 | self.dashr_hostlog_directory = os.path.join(self.dashr_log_directory, "hosts") 102 | if not os.path.exists(self.dashr_hostlog_directory): 103 | os.makedirs(self.dashr_hostlog_directory) 104 | 105 | self.dashr_hostlog = os.path.join(self.dashr_log_directory, "dashr_log_hostlist.yaml") 106 | self.dashr_errorlog = os.path.join(self.dashr_log_directory, "dashr_log_hostlog.log") 107 | if not os.path.exists(self.dashr_hostlog): 108 | refresh_host_yaml(self.dashr_hostlog, []) 109 | except: 110 | print "ERROR: Dashr callback plug-in init failed.\n%s\n" % (str(sys.exc_info())) 111 | this_script = os.path.realpath(__file__) 112 | os.rename(this_script, "%s.original" % this_script) 113 | print "For now we have renamed '%s' to '%s.original'. Report the issue, and re-apply the file once fixed." % (this_script, this_script) 114 | sys.exit(0) 115 | 116 | def on_any(self, *args, **kwargs): 117 | pass 118 | 119 | def runner_on_failed(self, host, res, ignore_errors=False): 120 | try: 121 | host_yaml = get_host_yaml(self.dashr_hostlog, self.dashr_hostlog_directory, host) 122 | _details = prepare_details(self, res, "failed") 123 | state_to_yaml(host_yaml, _details) 124 | except: 125 | err_msg = "* %s for 'runner_on_failed'\n%s\n---\n\n" % (host, str(sys.exc_info())) 126 | log_error(self.dashr_errorlog, err_msg) 127 | 128 | def runner_on_ok(self, host, res): 129 | try: 130 | host_yaml = get_host_yaml(self.dashr_hostlog, self.dashr_hostlog_directory, host) 131 | _details = prepare_details(self, res, "ok") 132 | state_to_yaml(host_yaml, _details) 133 | except: 134 | err_msg = "* %s for 'runner_on_ok'\n%s\n---\n\n" % (host, str(sys.exc_info())) 135 | log_error(self.dashr_errorlog, err_msg) 136 | 137 | def runner_on_error(self, host, msg): 138 | pass 139 | 140 | def runner_on_skipped(self, host, item=None): 141 | pass 142 | 143 | def runner_on_unreachable(self, host, res): 144 | try: 145 | host_yaml = get_host_yaml(self.dashr_hostlog, self.dashr_hostlog_directory, host) 146 | _details = prepare_details(self, res, "unreachable") 147 | state_to_yaml(host_yaml, _details) 148 | except: 149 | err_msg = "* %s for 'runner_on_unreachable'\n%s\n---\n\n" % (host, str(sys.exc_info())) 150 | log_error(self.dashr_errorlog, err_msg) 151 | 152 | def runner_on_no_hosts(self): 153 | pass 154 | 155 | def runner_on_async_poll(self, host, res, jid, clock): 156 | try: 157 | host_yaml = get_host_yaml(self.dashr_hostlog, self.dashr_hostlog_directory, host) 158 | state_to_yaml(host_yaml, res) 159 | except: 160 | err_msg = "* %s for 'runner_on_async_poll'\n%s\n---\n\n" % (host, str(sys.exc_info())) 161 | log_error(self.dashr_errorlog, err_msg) 162 | 163 | def runner_on_async_ok(self, host, res, jid): 164 | try: 165 | host_yaml = get_host_yaml(self.dashr_hostlog, self.dashr_hostlog_directory, host) 166 | _details = prepare_details(self, res, "ok") 167 | state_to_yaml(host_yaml, _details) 168 | except: 169 | err_msg = "* %s for 'runner_on_async_ok'\n%s\n---\n\n" % (host, str(sys.exc_info())) 170 | log_error(self.dashr_errorlog, err_msg) 171 | 172 | def runner_on_async_failed(self, host, res, jid): 173 | try: 174 | host_yaml = get_host_yaml(self.dashr_hostlog, self.dashr_hostlog_directory, host) 175 | _details = prepare_details(self, res, "failed") 176 | state_to_yaml(host_yaml, _details) 177 | except: 178 | err_msg = "* %s for 'runner_on_async_failed'\n%s\n---\n\n" % (host, str(sys.exc_info())) 179 | log_error(self.dashr_errorlog, err_msg) 180 | 181 | def playbook_on_start(self): 182 | pass 183 | 184 | def playbook_on_notify(self, host, handler): 185 | pass 186 | 187 | def playbook_on_no_hosts_matched(self): 188 | pass 189 | 190 | def playbook_on_no_hosts_remaining(self): 191 | pass 192 | 193 | def playbook_on_task_start(self, name, is_conditional): 194 | pass 195 | 196 | def playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None): 197 | pass 198 | 199 | def playbook_on_setup(self): 200 | pass 201 | 202 | def playbook_on_import_for_host(self, host, imported_file): 203 | pass 204 | 205 | def playbook_on_not_import_for_host(self, host, missing_file): 206 | pass 207 | 208 | def playbook_on_play_start(self, pattern): 209 | pass 210 | 211 | def playbook_on_stats(self, stats): 212 | pass 213 | -------------------------------------------------------------------------------- /config/js/main.data.js: -------------------------------------------------------------------------------- 1 | /* 2 | * contains Ansible related data 3 | * the only file needing modification per Ansible setup 4 | * can be generaed using *WIP* 5 | */ 6 | 7 | var inventories = ['env.alpha', 'env.beta']; 8 | var inventories_www_path = "/dummy-ansible-files/inventories"; 9 | var group_vars_www_path = "/dummy-ansible-files/group_vars"; 10 | var host_vars_www_path = "/dummy-ansible-files/host_vars"; 11 | 12 | //var playbook = ['pb01', 'pb02', 'pb03', 'pb04', 'pb05']; 13 | var playbooks = ['pb04', 'pb05']; 14 | var playbooks_www_path = "/dummy-ansible-files"; 15 | 16 | var roles = ['memcached', 'ntp', 'bind', 'mysql', 'nginx', 'redis']; 17 | var roles_www_path = "/dummy-ansible-files/roles"; 18 | 19 | var dashr_log_directory = "/dummy-ansible-files/logs/hosts"; 20 | var dashr_log_hostlist = "/dummy-ansible-files/logs/dashr_log_hostlist.yaml"; 21 | -------------------------------------------------------------------------------- /dashr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func redirect(w http.ResponseWriter, r *http.Request) { 11 | http.Redirect(w, r, "/www-data", 301) 12 | } 13 | 14 | func main() { 15 | dashr_ip := flag.String("fqdn", "127.0.0.1", "IP/FQDN to run HTTP listener at") 16 | dashr_port := flag.String("http", "8001", "port to run HTTP listener at") 17 | www_data := flag.String("www", "www-data", "path to ansible dashr static site content") 18 | ansible_setup := flag.String("ansible", "dummy-ansible-files", "path to ansible setup root of Playbooks, Roles Dir") 19 | dashr_config := flag.String("config", "config", "path to fetch/save Config used by Static Site Content") 20 | flag.Parse() 21 | 22 | connection_string := fmt.Sprintf("%s:%s", *dashr_ip, *dashr_port) 23 | www_data_uri := fmt.Sprintf("/%s/", *www_data) 24 | ansible_setup_uri := fmt.Sprintf("/%s/", *ansible_setup) 25 | dashr_config_uri := fmt.Sprintf("/%s/", *dashr_config) 26 | 27 | dashr_fs := http.FileServer(http.Dir(*www_data)) 28 | http.Handle(www_data_uri, http.StripPrefix(www_data_uri, dashr_fs)) 29 | 30 | ansible_fs := http.FileServer(http.Dir(*ansible_setup)) 31 | http.Handle(ansible_setup_uri, http.StripPrefix(ansible_setup_uri, ansible_fs)) 32 | 33 | config_fs := http.FileServer(http.Dir(*dashr_config)) 34 | http.Handle(dashr_config_uri, http.StripPrefix(dashr_config_uri, config_fs)) 35 | 36 | http.HandleFunc("/", redirect) 37 | log.Println("Ansible Dashr @", connection_string) 38 | if err := http.ListenAndServe(connection_string, nil); err != nil { 39 | fmt.Println("ERROR: Failed to start server.", err.Error()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /dummy-ansible-files/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | callback_plugins = ../callback 3 | -------------------------------------------------------------------------------- /dummy-ansible-files/group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | some_path: "/tmp/some" 4 | someone_path: "{{ some_path }}/one" 5 | something_path: "{{ some_path }}/thing" 6 | somebody_path: "{{ some_path }}/body" 7 | somewhere_path: "{{ some_path }}/where" 8 | somehow_path: "{{ some_path }}/how" 9 | 10 | temp_path: "/tmp/temp" 11 | 12 | this_user: "webserver" 13 | this_group: "wheel" 14 | -------------------------------------------------------------------------------- /dummy-ansible-files/group_vars/env.alpha: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | some_path: /tmp/alpha/some 4 | someone_path: {{ some_path }}/one 5 | something_path: {{ some_path }}/thing 6 | somebody_path: {{ some_path }}/body 7 | somewhere_path: {{ some_path }}/where 8 | somehow_path: {{ some_path }}/how 9 | -------------------------------------------------------------------------------- /dummy-ansible-files/host_vars/db1.alpha.example.com: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | this_user: dbuser01 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/host_vars/db2.alpha.example.com: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | this_user: dbuser02 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/inventories/env.alpha: -------------------------------------------------------------------------------- 1 | [databases] 2 | db1.alpha.example.com 3 | db2.alpha.example.com 4 | 5 | [appservers] 6 | some-app.alpha.example.com 7 | other-app.alpha.example.com 8 | 9 | [api] 10 | any-api.alpha.example.com 11 | external-api.alpha.example.com 12 | 13 | [alpha:children] 14 | databases ansible_user=dba01 15 | appservers ansible_user=dev01 16 | api ansible_user=dev01 17 | -------------------------------------------------------------------------------- /dummy-ansible-files/inventories/env.beta: -------------------------------------------------------------------------------- 1 | [databases] 2 | db1.beta.example.com 3 | db2.beta.example.com 4 | 5 | [appservers] 6 | some-app.beta.example.com 7 | other-app.beta.example.com 8 | 9 | [api] 10 | any-api.beta.example.com 11 | external-api.beta.example.com 12 | 13 | [alpha:children] 14 | databases ansible_user=dba01 15 | appservers ansible_user=dev01 16 | api ansible_user=dev01 17 | -------------------------------------------------------------------------------- /dummy-ansible-files/inventories/env.local: -------------------------------------------------------------------------------- 1 | [local] 2 | 127.0.0.1 ansible_connection=local 3 | -------------------------------------------------------------------------------- /dummy-ansible-files/logs/dashr_log_hostlist.yaml: -------------------------------------------------------------------------------- 1 | [127.0.0.1] 2 | -------------------------------------------------------------------------------- /dummy-ansible-files/logs/hosts/127.0.0.1: -------------------------------------------------------------------------------- 1 | sample-playbook::debug: 2 | details: {msg: yeah its running, playbook_name: sample-playbook} 3 | name: sample-playbook::debug 4 | state: ok 5 | sample-playbook::fail: 6 | details: {msg: induced failure to check dashboard reaction, playbook_name: sample-playbook} 7 | name: sample-playbook::fail 8 | state: failed 9 | sample-playbook::get_url: 10 | details: {msg: file already exists, playbook_name: sample-playbook} 11 | name: sample-playbook::get_url 12 | state: ok 13 | -------------------------------------------------------------------------------- /dummy-ansible-files/pb01.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook deploys a simple ntp and bind pkg 3 | 4 | - hosts: tomcat-servers 5 | user: root 6 | 7 | roles: 8 | - ntp 9 | - bind 10 | -------------------------------------------------------------------------------- /dummy-ansible-files/pb02.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # this playbook apply httpd and start it at webservers; create tmp dir 3 | 4 | - hosts: webservers 5 | vars: 6 | http_port: 80 7 | max_clients: 200 8 | remote_user: root 9 | tasks: 10 | - name: ensure apache is at the latest version 11 | yum: pkg=httpd state=latest 12 | - name: ensure apache is running 13 | service: name=httpd state=started 14 | - name: user tmp dir 15 | file: state=directory path=/tmp/{{ ansible_user }} 16 | notify: 17 | - restart apache 18 | handlers: 19 | - name: restart apache 20 | service: name=httpd state=restarted 21 | -------------------------------------------------------------------------------- /dummy-ansible-files/pb03.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # this playbook apply pb01 with user=timmy+alice+bob also with tom 3 | tasks: 4 | - include: pb01.yml wp_user=timmy 5 | - include: pb01.yml wp_user=alice 6 | - include: pb01.yml wp_user=bob 7 | - include: pb01.yml 8 | vars: 9 | wp_user: tom 10 | some_list_variable: 11 | - alpha 12 | - beta 13 | - gamma 14 | -------------------------------------------------------------------------------- /dummy-ansible-files/pb04.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook says hi and includes pb01,pb02 3 | - name: this is a play at the top level of a file 4 | hosts: all 5 | remote_user: root 6 | tasks: 7 | - name: say hi 8 | tags: foo 9 | shell: echo "hi..." 10 | 11 | - include: pb01.yml 12 | - include: pb02.yml 13 | -------------------------------------------------------------------------------- /dummy-ansible-files/pb05.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook applies ntp at alpha, nginx+redis at app, mysql+memcahced at db, bind+memchached at api 3 | 4 | - hosts: alpha 5 | roles: 6 | - ntp 7 | 8 | - hosts: appservers 9 | roles: 10 | - { role: nginx, dir: '/opt/www', port: 8800 } 11 | - { role: redis, dir: '/opt/redis', port: 8880 } 12 | 13 | - hosts: databases 14 | roles: 15 | - mysql 16 | - memcached 17 | 18 | - hosts: api 19 | roles: 20 | - bind 21 | - memcached 22 | - { role: redis, dir: '/opt/redis', port: 8880 } 23 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/resmo/ansible-role-bind.png?branch=master)](https://travis-ci.org/resmo/ansible-role-bind) 2 | 3 | # Ansible Bind Role 4 | 5 | An ansible role for installing and managing bind, acting as primary and/or secondary nameserver. 6 | It does also copy the master zone files (`bind_masterzones_path`), but however, the zone files must exist. 7 | 8 | 9 | ## Configuration: 10 | 11 | Define where your zones files are stored: 12 | 13 | bind_masterzones_path: path/to/zones_dir 14 | 15 | Configure the domains of the zones for a bind act as primary nameserver: 16 | 17 | bind_config_master_zones: 18 | - name: example.com 19 | - name: example2.com 20 | - name: example3.com 21 | 22 | Optionally: If your zone should be synced with secondary nameservers, define the IPs of those: 23 | 24 | bind_config_master_allow_transfer: 25 | - 127.0.0.1 26 | - 127.0.0.2 27 | 28 | Optionally: If your nameservers acts as a secondary nameserver, here is a sample setup: 29 | 30 | bind_config_slave_zones: 31 | - name: example.net 32 | masters: [ '127.1.0.1', '127.1.0.2' ] 33 | zones: 34 | - example.net 35 | - example.org 36 | 37 | 38 | ## Dependencies 39 | 40 | None. 41 | 42 | 43 | ## Example Playbook 44 | 45 | --- 46 | - hosts: nameservers 47 | remote_user: root 48 | roles: 49 | - { role: resmo.bind } 50 | 51 | 52 | ## License 53 | 54 | BSD 55 | 56 | 57 | ## Author Information 58 | 59 | René Moser 60 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | bind_config_master_zones: [] 3 | bind_config_master_allow_transfer: [] 4 | bind_config_master_forwarders: [ '0.0.0.0' ] 5 | bind_config_slave_zones: [] 6 | bind_service_state: started 7 | bind_service_enabled: yes 8 | bind_pkg_state: installed 9 | bind_base_zones_path: '/var/lib/bind' 10 | bind_masterzones_path: 'masters' 11 | bind_slavezones_path: 'slaves' 12 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/files/masters/db.example.com: -------------------------------------------------------------------------------- 1 | $TTL 4h 2 | $ORIGIN example.com. 3 | @ IN SOA ns1.example.com. hostmaster.example.com. ( 4 | 2013092801 ; Serial 5 | 1d ; slave refresh (1 day) 6 | 2h ; slave retry time in case of a problem (2 hours) 7 | 2w ; slave expiration time (2 weeks) 8 | 2d ; minimum caching time in case of failed lookups (2 days) 9 | ) 10 | IN NS ns1.example.com. 11 | www IN A 127.0.0.1 12 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/files/named.conf: -------------------------------------------------------------------------------- 1 | // This is the primary configuration file for the BIND DNS server named. 2 | // 3 | // Please read /usr/share/doc/bind9/README.Debian.gz for information on the 4 | // structure of BIND configuration files in Debian, *BEFORE* you customize 5 | // this configuration file. 6 | // 7 | // If you are just adding zones, please do that in /etc/bind/named.conf.local 8 | 9 | include "/etc/bind/named.conf.options"; 10 | 11 | // prime the server with knowledge of the root servers 12 | zone "." { 13 | type hint; 14 | file "/etc/bind/db.root"; 15 | }; 16 | 17 | // be authoritative for the localhost forward and reverse zones, and for 18 | // broadcast zones as per RFC 1912 19 | 20 | zone "localhost" { 21 | type master; 22 | file "/etc/bind/db.local"; 23 | }; 24 | 25 | zone "127.in-addr.arpa" { 26 | type master; 27 | file "/etc/bind/db.127"; 28 | }; 29 | 30 | zone "0.in-addr.arpa" { 31 | type master; 32 | file "/etc/bind/db.0"; 33 | }; 34 | 35 | zone "255.in-addr.arpa" { 36 | type master; 37 | file "/etc/bind/db.255"; 38 | }; 39 | 40 | include "/etc/bind/named.conf.local"; 41 | include "/etc/bind/named.conf.local.master"; 42 | include "/etc/bind/named.conf.local.slave"; 43 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart bind 3 | service: name={{ bind_service_name }} state=restarted 4 | 5 | - name: reload bind 6 | service: name={{ bind_service_name }} state=reloaded 7 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: René Moser 4 | company: Moser Systems 5 | license: MIT 6 | min_ansible_version: 1.4 7 | 8 | platforms: 9 | - name: Ubuntu 10 | versions: 11 | - all 12 | - name: Debian 13 | versions: 14 | - all 15 | categories: 16 | - system 17 | 18 | dependencies: [] 19 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/role.yml: -------------------------------------------------------------------------------- 1 | - hosts: localhost 2 | vars: 3 | bind_config_master_zones: 4 | - name: example.com 5 | 6 | bind_config_master_allow_transfer: 7 | - 127.0.0.1 8 | - 127.0.0.2 9 | 10 | bind_config_slave_zones: 11 | - name: example.net 12 | masters: [ '127.1.0.1', '127.1.0.2' ] 13 | zones: 14 | - example.net 15 | - example.org 16 | roles: 17 | - ansible-role-bind 18 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install bind packages 3 | apt: pkg={{ item }} state={{ bind_pkg_state }} 4 | with_items: bind_pkgs 5 | tags: package 6 | 7 | - name: setup zone directories 8 | file: dest={{ bind_base_zones_path }}/{{ item }} state=directory owner={{ bind_user }} group={{ bind_group }} mode=0755 9 | with_items: 10 | - masters 11 | - slaves 12 | tags: configuration 13 | 14 | - name: setup zones 15 | action: template src=named.conf.local.{{ item }}.j2 dest={{ bind_config_basepath }}/named.conf.local.{{ item }} owner={{ bind_user }} group={{ bind_group }} mode=0600 16 | with_items: 17 | - master 18 | - slave 19 | notify: reload bind 20 | tags: configuration 21 | 22 | - name: configure bind 23 | copy: src=named.conf dest={{ bind_config_basepath }}/named.conf owner={{ bind_user }} group={{ bind_group }} mode=0600 validate='named-checkconf %s' 24 | notify: restart bind 25 | tags: configuration 26 | 27 | - name: configure bind options 28 | template: src=named.conf.options.j2 dest={{ bind_config_basepath }}/named.conf.options owner={{ bind_user }} group={{ bind_group }} mode=0600 validate='named-checkconf %s' 29 | notify: restart bind 30 | tags: configuration 31 | 32 | - name: Copy master zone files 33 | copy: src={{ bind_masterzones_path }}/db.{{ item.name }} dest={{ bind_base_zones_path }}/{{bind_masterzones_path}} owner={{ bind_user }} group={{ bind_group }} 34 | with_items: bind_config_master_zones 35 | notify: restart bind 36 | tags: zones 37 | 38 | - name: start/stop bind service 39 | service: name={{ bind_service_name }} state={{ bind_service_state }} enabled={{ bind_service_enabled }} 40 | tags: service 41 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/templates/named.conf.local.master.j2: -------------------------------------------------------------------------------- 1 | ## {{ ansible_managed }} 2 | 3 | {% for master_zone in bind_config_master_zones %} 4 | zone "{{ master_zone.name }}" { 5 | type master; 6 | file "{{bind_base_zones_path}}/{{bind_masterzones_path}}/db.{{ master_zone.name }}"; 7 | {% if master_zone.allow_transfer is defined %} 8 | allow-transfer { 9 | {% for allow_transfer in master_zone.allow_transfer %} 10 | {{ allow_transfer }}; 11 | {% endfor %} 12 | }; 13 | {% endif %} 14 | {% if master_zone.allow_update is defined %} 15 | allow-update { 16 | {% for allow_update in master_zone.allow_update %} 17 | {{ allow_update }}; 18 | {% endfor %} 19 | }; 20 | {% endif %} 21 | }; 22 | 23 | {% endfor %} 24 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/templates/named.conf.local.slave.j2: -------------------------------------------------------------------------------- 1 | ## {{ ansible_managed }} 2 | {% for slave_zone in bind_config_slave_zones %} 3 | ######## {{ slave_zone.name }} ({{ slave_zone.zones|count }} zones) 4 | {% for zone in slave_zone.zones %} 5 | zone "{{ zone }}" { 6 | type slave; 7 | file "{{bind_base_zones_path}}/{{bind_slavezones_path}}/db.{{ zone }}"; 8 | masters { 9 | {% for master in slave_zone.masters %} 10 | {{ master }}; 11 | {% endfor %} 12 | }; 13 | }; 14 | {% endfor %} 15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/templates/named.conf.options.j2: -------------------------------------------------------------------------------- 1 | // {{ ansible_managed }} 2 | 3 | options { 4 | directory "/var/cache/bind"; 5 | 6 | // If there is a firewall between you and nameservers you want 7 | // to talk to, you might need to uncomment the query-source 8 | // directive below. Previous versions of BIND always asked 9 | // questions using port 53, but BIND 8.1 and later use an unprivileged 10 | // port by default. 11 | 12 | //query-source address * port 53; 13 | 14 | query-source address * port *; 15 | 16 | transfer-source *; 17 | 18 | notify-source *; 19 | 20 | allow-transfer { 21 | {% for allow_transfer in bind_config_master_allow_transfer %} 22 | {{ allow_transfer }}; 23 | {% endfor %} 24 | }; 25 | 26 | notify yes; 27 | 28 | also-notify { 29 | }; 30 | 31 | //provide-ixfr no ; 32 | 33 | // If your ISP provided one or more IP addresses for stable 34 | // nameservers, you probably want to use them as forwarders. 35 | // Uncomment the following block, and insert the addresses replacing 36 | // the all-0's placeholder. 37 | 38 | forwarders { 39 | {% for forwarders in bind_config_master_forwarders %} 40 | {{ forwarders }}; 41 | {% endfor %} 42 | }; 43 | 44 | //dnssec-enable yes; 45 | //dnssec-validation yes; 46 | 47 | auth-nxdomain no; # conform to RFC1035 48 | 49 | listen-on-v6 { any; }; 50 | 51 | allow-query { any; }; // This is the default 52 | recursion no; // Do not provide recursive service 53 | zone-statistics yes; 54 | }; 55 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/bind/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | bind_config_basepath: /etc/bind 3 | bind_user: bind 4 | bind_group: bind 5 | bind_service_name: bind9 6 | bind_pkgs: 7 | - bind9 8 | - dnsutils 9 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/README.md: -------------------------------------------------------------------------------- 1 | memcached 2 | ======== 3 | 4 | This role helps to install a memcached server on the target host. 5 | 6 | Requirements 7 | ------------ 8 | 9 | This role requires Ansible 1.4 or higher, and platform requirements are listed 10 | in the metadata file. 11 | 12 | Role Variables 13 | -------------- 14 | 15 | The variables that can be passed to this role and a brief description about 16 | them are as follows: 17 | 18 | memcached_port: 11211 # The port in which memcached server should be listening 19 | memcached_listen_address: 0.0.0.0 # The IP address to listen on 20 | memcached_max_conn: 1024 # The number of max concurrent connections it should accept 21 | memcached_cache_size: 64 # The cache size 22 | memcached_fs_file_max: 756024 # The kernel parameter for max number of file handles 23 | 24 | Example 25 | ------- 26 | 27 | The following play setup's memcached with a different port number and 28 | available memory. 29 | 30 | - hosts: all 31 | sudo: true 32 | roles: 33 | - {role: bennojoy.memcached, memcached_port: 11244, memcached_cache_size: 512 } 34 | 35 | Dependencies 36 | ------------ 37 | 38 | None 39 | 40 | License 41 | ------- 42 | 43 | BSD 44 | 45 | Author Information 46 | ------------------ 47 | 48 | Benno Joy 49 | 50 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | memcached_port: 11211 4 | memcached_listen_address: 0.0.0.0 5 | memcached_max_conn: 1024 6 | memcached_cache_size: 64 7 | memcached_fs_file_max: 756024 8 | 9 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart memcached 3 | service: name=memcached state=restarted 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "Benno Joy" 4 | company: AnsibleWorks 5 | license: BSD 6 | min_ansible_version: 1.4 7 | platforms: 8 | - name: EL 9 | versions: 10 | - 5 11 | - 6 12 | - name: Fedora 13 | versions: 14 | - 16 15 | - 17 16 | - 18 17 | - name: Ubuntu 18 | versions: 19 | - precise 20 | - quantal 21 | - raring 22 | - saucy 23 | categories: 24 | - web 25 | dependencies: [] 26 | 27 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install the memcached packages 4 | yum: name={{ item }} state=present 5 | with_items: memcached_redhat_pkgs 6 | when: ansible_os_family == "RedHat" 7 | 8 | - name: Install the memcached packages 9 | apt: name={{ item }} state=present update_cache=yes 10 | with_items: memcached_ubuntu_pkgs 11 | environment: env 12 | when: ansible_os_family == "Debian" 13 | 14 | - name: Copy the client configuration file 15 | template: src=memcached_redhat.j2 dest=/etc/sysconfig/memcached 16 | notify: 17 | - restart memcached 18 | when: ansible_os_family == "RedHat" 19 | 20 | - name: Copy the client configuration file 21 | template: src=memcached_debian.j2 dest=/etc/memcached.conf 22 | notify: restart memcached 23 | when: ansible_os_family == "Debian" 24 | 25 | - name: Set the max open file descriptors 26 | sysctl: name=fs.file-max value={{ memcached_fs_file_max }} state=present ignoreerrors=yes 27 | 28 | - name: start the memcached service 29 | service: name=memcached state=started enabled=yes 30 | 31 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/templates/memcached_debian.j2: -------------------------------------------------------------------------------- 1 | # memcached default config file 2 | # 2003 - Jay Bonci 3 | # This configuration file is read by the start-memcached script provided as 4 | # part of the Debian GNU/Linux distribution. 5 | 6 | # Run memcached as a daemon. This command is implied, and is not needed for the 7 | # daemon to run. See the README.Debian that comes with this package for more 8 | # information. 9 | -d 10 | 11 | # Log memcached's output to /var/log/memcached 12 | logfile /var/log/memcached.log 13 | 14 | # Be verbose 15 | # -v 16 | 17 | # Be even more verbose (print client commands as well) 18 | # -vv 19 | 20 | # Start with a cap of 64 megs of memory. It's reasonable, and the daemon default 21 | # Note that the daemon will grow to this size, but does not start out holding this much 22 | # memory 23 | -m {{ memcached_cache_size }} 24 | 25 | # Default connection port is 11211 26 | -p {{ memcached_port }} 27 | 28 | # Run the daemon as root. The start-memcached will default to running as root if no 29 | # -u command is present in this config file 30 | -u memcache 31 | 32 | # Specify which IP address to listen on. The default is to listen on all IP addresses 33 | # This parameter is one of the only security measures that memcached has, so make sure 34 | # it's listening on a firewalled interface. 35 | -l {{ memcached_listen_address }} 36 | 37 | # Limit the number of simultaneous incoming connections. The daemon default is 1024 38 | -c {{ memcached_max_conn }} 39 | 40 | # Lock down all paged memory. Consult with the README and homepage before you do this 41 | # -k 42 | 43 | # Return error when memory is exhausted (rather than removing items) 44 | # -M 45 | 46 | # Maximize core file limit 47 | # -r 48 | 49 | 50 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/templates/memcached_redhat.j2: -------------------------------------------------------------------------------- 1 | PORT={{ memcached_port }} 2 | USER="memcached" 3 | MAXCONN={{ memcached_max_conn }} 4 | CACHESIZE={{ memcached_cache_size }} 5 | OPTIONS="-l {{ memcached_listen_address }}" 6 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/memcached/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | env: 4 | RUNLEVEL: 1 5 | 6 | memcached_redhat_pkgs: 7 | - libselinux-python 8 | - memcached 9 | 10 | memcached_ubuntu_pkgs: 11 | - python-selinux 12 | - memcached 13 | 14 | 15 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/README.md: -------------------------------------------------------------------------------- 1 | MySQL Server 2 | ============ 3 | 4 | This roles helps to install MySQL Server across RHEL and Ubuntu variants. 5 | Apart from installing the MySQL Server, it applies basic hardening, like 6 | securing the root account with password, and removing test databases. The role 7 | can also be used to add databases to the MySQL server and create users in the 8 | database. It also supports configuring the databases for replication--both 9 | master and slave can be configured via this role. 10 | 11 | Requirements 12 | ------------ 13 | 14 | This role requires Ansible 1.4 or higher, and platform requirements are listed 15 | in the metadata file. 16 | 17 | Role Variables 18 | -------------- 19 | 20 | The variables that can be passed to this role and a brief description about 21 | them are as follows: 22 | 23 | mysql_port: 3306 # The port for mysql server to listen 24 | mysql_bind_address: "0.0.0.0" # The bind address for mysql server 25 | mysql_root_db_pass: foobar # The root DB password 26 | 27 | # A list that has all the databases to be 28 | # created and their replication status: 29 | mysql_db: 30 | - name: foo 31 | replicate: yes 32 | - name: bar 33 | replicate: no 34 | 35 | # A list of the mysql users to be created 36 | # and their password and privileges: 37 | mysql_users: 38 | - name: benz 39 | pass: foobar 40 | priv: "*.*:ALL" 41 | 42 | # If the database is replicated the users 43 | # to be used for replication: 44 | mysql_repl_user: 45 | - name: repl 46 | pass: foobar 47 | 48 | # The role of this server in replication: 49 | mysql_repl_role: master 50 | 51 | # A unique id for the mysql server (used in replication): 52 | mysql_db_id: 7 53 | 54 | Examples 55 | -------- 56 | 57 | 1) Install MySQL Server and set the root password, but don't create any 58 | database or users. 59 | 60 | - hosts: all 61 | roles: 62 | - {role: mysql, mysql_root_db_pass: foobar, mysql_db: none, mysql_users: none } 63 | 64 | 2) Install MySQL Server and create 2 databases and 2 users. 65 | 66 | - hosts: all 67 | roles: 68 | - {role: mysql, mysql_db: [{name: benz}, 69 | {name: benz2}], 70 | mysql_users: [{name: ben3, pass: foobar, priv: "*.*:ALL"}, 71 | {name: ben2, pass: foo}] } 72 | 73 | Note: If users are specified and password/privileges are not specified, then 74 | default values are set. 75 | 76 | 3) Install MySQL Server and create 2 databases and 2 users and configure the 77 | database as replication master with one database configured for replication. 78 | 79 | - hosts: all 80 | roles: 81 | - {role: mysql, mysql_db: [{name: benz, replicate: yes }, 82 | { name: benz2, replicate: no}], 83 | mysql_users: [{name: ben3, pass: foobar, priv: "*.*:ALL"}, 84 | {name: ben2, pass: foo}], 85 | mysql_repl_user: [{name: repl, pass: foobar}] } 86 | 87 | 4) A fully installed/configured MySQL Server with master and slave 88 | replication. 89 | 90 | - hosts: master 91 | roles: 92 | - {role: mysql, mysql_db: [{name: benz}, {name: benz2}], 93 | mysql_users: [{name: ben3, pass: foobar, priv: "*.*:ALL"}, 94 | {name: ben2, pass: foo}], 95 | mysql_db_id: 8 } 96 | 97 | - hosts: slave 98 | roles: 99 | - {role: mysql, mysql_db: none, mysql_users: none, 100 | mysql_repl_role: slave, mysql_repl_master: vm2, 101 | mysql_db_id: 9, mysql_repl_user: [{name: repl, pass: foobar}] } 102 | 103 | Note: When configuring the full replication please make sure the master is 104 | configured via this role and the master is available in inventory and facts 105 | have been gathered for master. The replication tasks assume the database is 106 | new and has no data. 107 | 108 | 109 | Dependencies 110 | ------------ 111 | 112 | None 113 | 114 | License 115 | ------- 116 | 117 | BSD 118 | 119 | Author Information 120 | ------------------ 121 | 122 | Benno Joy 123 | 124 | 125 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | mysql_port: 3306 4 | mysql_bind_address: "0.0.0.0" 5 | mysql_root_db_pass: foobar 6 | 7 | mysql_db: 8 | - name: foo 9 | replicate: yes 10 | - name: bar 11 | replicate: no 12 | 13 | mysql_users: 14 | - name: benz 15 | pass: foobar 16 | priv: "*.*:ALL" 17 | 18 | mysql_repl_user: 19 | - name: repl 20 | pass: foobar 21 | 22 | mysql_repl_role: master 23 | mysql_db_id: 7 24 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart mysql 3 | service: name={{ mysql_service }} state=restarted 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "Benno Joy" 4 | company: AnsibleWorks 5 | license: license (BSD) 6 | min_ansible_version: 1.4 7 | platforms: 8 | - name: EL 9 | versions: 10 | - 5 11 | - 6 12 | - name: Fedora 13 | versions: 14 | - 16 15 | - 17 16 | - 18 17 | - name: Ubuntu 18 | versions: 19 | - precise 20 | - quantal 21 | - raring 22 | - saucy 23 | categories: 24 | - database:sql 25 | dependencies: [] 26 | 27 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add the OS specific variables 3 | include_vars: "{{ ansible_os_family }}.yml" 4 | 5 | - name: Install the mysql packages in Redhat derivatives 6 | yum: name={{ item }} state=installed 7 | with_items: mysql_pkgs 8 | when: ansible_os_family == 'RedHat' 9 | 10 | - name: Install the mysql packages in Debian derivatives 11 | apt: name={{ item }} state=installed update_cache=yes 12 | with_items: mysql_pkgs 13 | environment: env 14 | when: ansible_os_family == 'Debian' 15 | 16 | - name: Copy the my.cnf file 17 | template: src=my.cnf.{{ ansible_os_family }}.j2 dest={{ mysql_conf_dir }}/my.cnf 18 | notify: 19 | - restart mysql 20 | 21 | - name: Create the directory /etc/mysql/conf.d 22 | file: path=/etc/mysql/conf.d state=directory 23 | notify: 24 | - restart mysql 25 | 26 | - name: Start the mysql services Redhat 27 | service: name={{ mysql_service }} state=started enabled=yes 28 | 29 | - name: update mysql root password for all root accounts 30 | mysql_user: name=root host={{ item }} password={{ mysql_root_db_pass }} 31 | with_items: 32 | - "{{ ansible_hostname }}" 33 | - 127.0.0.1 34 | - ::1 35 | - localhost 36 | when: ansible_hostname != 'localhost' 37 | 38 | - name: update mysql root password for all root accounts 39 | mysql_user: name=root host={{ item }} password={{ mysql_root_db_pass }} 40 | with_items: 41 | - 127.0.0.1 42 | - ::1 43 | - localhost 44 | when: ansible_hostname == 'localhost' 45 | 46 | - name: copy .my.cnf file with root password credentials 47 | template: src=.my.cnf.j2 dest=~/.my.cnf mode=0600 48 | 49 | - name: ensure anonymous users are not in the database 50 | mysql_user: name='' host={{ item }} state=absent 51 | with_items: 52 | - localhost 53 | - "{{ ansible_hostname }}" 54 | 55 | - name: remove the test database 56 | mysql_db: name=test state=absent 57 | 58 | - name: Create the database's 59 | mysql_db: name={{ item.name }} state=present 60 | with_items: mysql_db 61 | when: mysql_db|lower() != 'none' 62 | 63 | - name: Create the database users 64 | mysql_user: name={{ item.name }} password={{ item.pass|default("foobar") }} 65 | priv={{ item.priv|default("*.*:ALL") }} state=present host={{ item.host | default("localhost") }} 66 | with_items: mysql_users 67 | when: mysql_users|lower() != 'none' 68 | 69 | - name: Create the replication users 70 | mysql_user: name={{ item.name }} host="%" password={{ item.pass|default("foobar") }} 71 | priv=*.*:"REPLICATION SLAVE" state=present 72 | with_items: mysql_repl_user 73 | when: mysql_repl_role == 'master' 74 | 75 | - name: Check if slave is already configured for replication 76 | mysql_replication: mode=getslave 77 | ignore_errors: true 78 | register: slave 79 | when: mysql_repl_role == 'slave' 80 | 81 | - name: Ensure the hostname entry for master is available for the client. 82 | lineinfile: dest=/etc/hosts regexp="{{ mysql_repl_master }}" line="{{ hostvars[mysql_repl_master].ansible_default_ipv4.address + " " + mysql_repl_master }}" state=present 83 | when: slave|failed and mysql_repl_role == 'slave' and mysql_repl_master is defined 84 | 85 | - name: Get the current master servers replication status 86 | mysql_replication: mode=getmaster 87 | delegate_to: "{{ mysql_repl_master }}" 88 | register: repl_stat 89 | when: slave|failed and mysql_repl_role == 'slave' and mysql_repl_master is defined 90 | 91 | - name: Change the master in slave to start the replication 92 | mysql_replication: mode=changemaster master_host={{ mysql_repl_master }} master_log_file={{ repl_stat.File }} master_log_pos={{ repl_stat.Position }} master_user={{ mysql_repl_user[0].name }} master_password={{ mysql_repl_user[0].pass }} 93 | when: slave|failed and mysql_repl_role == 'slave' and mysql_repl_master is defined 94 | 95 | 96 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/templates/.my.cnf.j2: -------------------------------------------------------------------------------- 1 | [client] 2 | user=root 3 | password={{ mysql_root_db_pass }} 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/templates/my.cnf.Debian.j2: -------------------------------------------------------------------------------- 1 | # 2 | # The MySQL database server configuration file. 3 | # 4 | [client] 5 | port = {{ mysql_port }} 6 | socket = /var/run/mysqld/mysqld.sock 7 | 8 | # This was formally known as [safe_mysqld]. Both versions are currently parsed. 9 | [mysqld_safe] 10 | socket = /var/run/mysqld/mysqld.sock 11 | nice = 0 12 | 13 | [mysqld] 14 | user = mysql 15 | pid-file = /var/run/mysqld/mysqld.pid 16 | socket = /var/run/mysqld/mysqld.sock 17 | port = {{ mysql_port }} 18 | basedir = /usr 19 | datadir = /var/lib/mysql 20 | tmpdir = /tmp 21 | lc-messages-dir = /usr/share/mysql 22 | skip-external-locking 23 | 24 | bind-address = {{ mysql_bind_address }} 25 | 26 | key_buffer = 16M 27 | max_allowed_packet = 16M 28 | thread_stack = 192K 29 | thread_cache_size = 8 30 | 31 | query_cache_limit = 1M 32 | query_cache_size = 16M 33 | log_error = /var/log/mysql/error.log 34 | server-id = {{ mysql_db_id }} 35 | 36 | {% if mysql_repl_role == 'master' %} 37 | log_bin = mysql-bin 38 | expire_logs_days = 10 39 | max_binlog_size = 100M 40 | 41 | {% if mysql_db is iterable and mysql_db is not string %} 42 | {% for i in mysql_db %} 43 | {% if i.replicate|default(1) %} 44 | binlog_do_db = {{ i.name }} 45 | {% endif %} 46 | {% endfor %} 47 | 48 | {% for i in mysql_db %} 49 | {% if not i.replicate|default(1) %} 50 | binlog_ignore_db = {{ i.name }} 51 | {% endif %} 52 | {% endfor %} 53 | {% endif %} 54 | {% endif %} 55 | 56 | !includedir /etc/mysql/conf.d/ 57 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/templates/my.cnf.RedHat.j2: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | datadir=/var/lib/mysql 3 | socket=/var/lib/mysql/mysql.sock 4 | user=mysql 5 | # Disabling symbolic-links is recommended to prevent assorted security risks 6 | symbolic-links=0 7 | port={{ mysql_port }} 8 | bind-address={{ mysql_bind_address }} 9 | server-id = {{ mysql_db_id }} 10 | 11 | {% if mysql_repl_role == 'master' %} 12 | log_bin = mysql-bin 13 | expire_logs_days = 10 14 | max_binlog_size = 100M 15 | 16 | {% for i in mysql_db %} 17 | {% if i.replicate|default(1) %} 18 | binlog_do_db = {{ i.name }} 19 | {% endif %} 20 | {% endfor %} 21 | 22 | {% for i in mysql_db %} 23 | {% if not i.replicate|default(1) %} 24 | binlog_ignore_db = {{ i.name }} 25 | {% endif %} 26 | {% endfor %} 27 | {% endif %} 28 | 29 | [mysqld_safe] 30 | log-error=/var/log/mysqld.log 31 | pid-file=/var/run/mysqld/mysqld.pid 32 | 33 | !includedir /etc/mysql/conf.d/ 34 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/vars/Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | mysql_pkgs: 4 | - python-selinux 5 | - mysql-server 6 | - python-mysqldb 7 | 8 | mysql_service: mysql 9 | mysql_conf_dir: "/etc/mysql/" 10 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | mysql_pkgs: 3 | - libselinux-python 4 | - mysql-server 5 | - MySQL-python 6 | 7 | mysql_service: mysqld 8 | 9 | mysql_conf_dir: "/etc/" 10 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/mysql/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | env: 3 | RUNLEVEL: 1 4 | 5 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/README.md: -------------------------------------------------------------------------------- 1 | nginx 2 | ===== 3 | 4 | This role installs and configures the nginx web server. The user can specify 5 | any http configuration parameters they wish to apply their site. Any number of 6 | sites can be added with configurations of your choice. 7 | 8 | Requirements 9 | ------------ 10 | 11 | This role requires Ansible 1.4 or higher and platform requirements are listed 12 | in the metadata file. 13 | 14 | Role Variables 15 | -------------- 16 | 17 | The variables that can be passed to this role and a brief description about 18 | them are as follows. 19 | 20 | # The max clients allowed 21 | nginx_max_clients: 512 22 | 23 | # A hash of the http paramters. Note that any 24 | # valid nginx http paramters can be added here. 25 | # (see the nginx documentation for details.) 26 | nginx_http_params: 27 | sendfile: "on" 28 | tcp_nopush: "on" 29 | tcp_nodelay: "on" 30 | keepalive_timeout: "65" 31 | access_log: "/var/log/nginx/access.log" 32 | error_log: "/var/log/nginx/error.log" 33 | 34 | # A list of hashs that define the servers for nginx, 35 | # as with http parameters. Any valid server parameters 36 | # can be defined here. 37 | nginx_sites: 38 | - server: 39 | file_name: foo 40 | listen: 8080 41 | server_name: localhost 42 | root: "/tmp/site1" 43 | location1: {name: /, try_files: "$uri $uri/ /index.html"} 44 | location2: {name: /images/, try_files: "$uri $uri/ /index.html"} 45 | - server: 46 | file_name: bar 47 | listen: 9090 48 | server_name: ansible 49 | root: "/tmp/site2" 50 | location1: {name: /, try_files: "$uri $uri/ /index.html"} 51 | location2: {name: /images/, try_files: "$uri $uri/ /index.html"} 52 | 53 | Examples 54 | ======== 55 | 56 | 1) Install nginx with HTTP directives of choices, but with no sites 57 | configured: 58 | 59 | - hosts: all 60 | roles: 61 | - {role: nginx, 62 | nginx_http_params: { sendfile: "on", 63 | access_log: "/var/log/nginx/access.log"}, 64 | nginx_sites: none } 65 | 66 | 67 | 2) Install nginx with different HTTP directives than previous example, but no 68 | sites configured. 69 | 70 | - hosts: all 71 | roles: 72 | - {role: nginx, 73 | nginx_http_params: { tcp_nodelay: "on", 74 | error_log: "/var/log/nginx/error.log"}, 75 | nginx_sites: none } 76 | 77 | Note: Please make sure the HTTP directives passed are valid, as this role 78 | won't check for the validity of the directives. See the nginx documentation 79 | for details. 80 | 81 | 3) Install nginx and add a site to the configuration. 82 | 83 | - hosts: all 84 | 85 | roles: 86 | - role: nginx, 87 | nginx_http_params: 88 | sendfile: "on" 89 | access_log: "/var/log/nginx/access.log" 90 | nginx_sites: 91 | - server: 92 | file_name: bar 93 | listen: 8080 94 | location1: {name: "/", try_files: "$uri $uri/ /index.html"} 95 | location2: {name: /images/, try_files: "$uri $uri/ /index.html"} 96 | 97 | Note: Each site added is represented by list of hashes, and the configurations 98 | generated are populated in `/etc/nginx/sites-available/` and have corresponding 99 | symlinks from `/etc/nginx/sites-enabled/` 100 | 101 | The file name for the specific site configurtaion is specified in the hash 102 | with the key "file_name", any valid server directives can be added to hash. 103 | For location directive add the key "location" suffixed by a unique number, the 104 | value for the location is hash, please make sure they are valid location 105 | directives. 106 | 107 | 4) Install Nginx and add 2 sites (different method) 108 | 109 | --- 110 | - hosts: all 111 | roles: 112 | - role: nginx 113 | nginx_http_params: 114 | sendfile: "on" 115 | access_log: "/var/log/nginx/access.log" 116 | nginx_sites: 117 | - server: 118 | file_name: foo 119 | listen: 8080 120 | server_name: localhost 121 | root: "/tmp/site1" 122 | location1: {name: /, try_files: "$uri $uri/ /index.html"} 123 | location2: {name: /images/, try_files: "$uri $uri/ /index.html"} 124 | - server: 125 | file_name: bar 126 | listen: 9090 127 | server_name: ansible 128 | root: "/tmp/site2" 129 | location1: {name: /, try_files: "$uri $uri/ /index.html"} 130 | location2: {name: /images/, try_files: "$uri $uri/ /index.html"} 131 | 132 | Dependencies 133 | ------------ 134 | 135 | None 136 | 137 | License 138 | ------- 139 | 140 | BSD 141 | 142 | Author Information 143 | ------------------ 144 | 145 | Benno Joy 146 | 147 | 148 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | nginx_max_clients: 512 4 | 5 | nginx_http_params: 6 | sendfile: "on" 7 | tcp_nopush: "on" 8 | tcp_nodelay: "on" 9 | keepalive_timeout: "65" 10 | 11 | nginx_log_dir: "/var/log/nginx" 12 | nginx_access_log_name: "access.log" 13 | nginx_error_log_name: "error.log" 14 | nginx_separete_logs_per_site: False 15 | 16 | nginx_sites: 17 | - server: 18 | file_name: foo 19 | listen: 8080 20 | server_name: localhost 21 | root: "/tmp/site1" 22 | location1: {name: /, try_files: "$uri $uri/ /index.html"} 23 | location2: {name: /images/, try_files: "$uri $uri/ /index.html"} 24 | - server: 25 | file_name: bar 26 | listen: 9090 27 | server_name: ansible 28 | root: "/tmp/site2" 29 | location1: {name: /, try_files: "$uri $uri/ /index.html"} 30 | location2: {name: /images/, try_files: "$uri $uri/ /index.html"} 31 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/files/epel.repo: -------------------------------------------------------------------------------- 1 | [epel] 2 | name=Extra Packages for Enterprise Linux 6 - $basearch 3 | baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch 4 | #mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch 5 | failovermethod=priority 6 | enabled=1 7 | gpgcheck=0 8 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 9 | 10 | [epel-debuginfo] 11 | name=Extra Packages for Enterprise Linux 6 - $basearch - Debug 12 | #baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/debug 13 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch 14 | failovermethod=priority 15 | enabled=0 16 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 17 | gpgcheck=1 18 | 19 | [epel-source] 20 | name=Extra Packages for Enterprise Linux 6 - $basearch - Source 21 | #baseurl=http://download.fedoraproject.org/pub/epel/6/SRPMS 22 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-6&arch=$basearch 23 | failovermethod=priority 24 | enabled=0 25 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 26 | gpgcheck=1 27 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart nginx 3 | service: name=nginx state=restarted 4 | 5 | - name: reload nginx 6 | service: name=nginx state=reloaded 7 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "Benno Joy" 4 | company: AnsibleWorks 5 | license: BSD 6 | min_ansible_version: 1.4 7 | platforms: 8 | - name: EL 9 | versions: 10 | - 5 11 | - 6 12 | - name: Fedora 13 | versions: 14 | - 16 15 | - 17 16 | - 18 17 | - name: Ubuntu 18 | versions: 19 | - precise 20 | - quantal 21 | - raring 22 | - saucy 23 | categories: 24 | - web 25 | dependencies: [] 26 | 27 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Install the selinux python module 4 | yum: name=libselinux-python state=present 5 | when: ansible_os_family == "RedHat" 6 | 7 | - name: Copy the epel packages 8 | copy: src=epel.repo dest=/etc/yum.repos.d/epel_ansible.repo 9 | when: ansible_os_family == "RedHat" 10 | 11 | - name: Install the nginx packages 12 | yum: name={{ item }} state=present 13 | with_items: redhat_pkg 14 | when: ansible_os_family == "RedHat" 15 | 16 | - name: Install the nginx packages 17 | apt: name={{ item }} state=present update_cache=yes 18 | with_items: ubuntu_pkg 19 | environment: env 20 | when: ansible_os_family == "Debian" 21 | 22 | - name: Create the directories for site specific configurations 23 | file: path=/etc/nginx/{{ item }} state=directory owner=root group=root mode=0755 24 | with_items: 25 | - "sites-available" 26 | - "sites-enabled" 27 | 28 | - name: Copy the nginx configuration file 29 | template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf 30 | notify: 31 | - restart nginx 32 | 33 | - name: Copy the nginx default configuration file 34 | template: src=default.conf.j2 dest=/etc/nginx/conf.d/default.conf 35 | 36 | - name: Copy the nginx default site configuration file 37 | template: src=default.j2 dest=/etc/nginx/sites-available/default 38 | 39 | - name: Create the link for site enabled specific configurations 40 | file: path=/etc/nginx/sites-enabled/default state=link src=/etc/nginx/sites-available/default 41 | 42 | - name: Create the configurations for sites 43 | template: src=site.j2 dest=/etc/nginx/sites-available/{{ item['server']['file_name'] }} 44 | with_items: nginx_sites 45 | when: nginx_sites|lower != 'none' 46 | 47 | - name: Create the links to enable site configurations 48 | file: path=/etc/nginx/sites-enabled/{{ item['server']['file_name'] }} state=link src=/etc/nginx/sites-available/{{ item['server']['file_name'] }} 49 | with_items: nginx_sites 50 | when: nginx_sites|lower != 'none' 51 | notify: 52 | - reload nginx 53 | 54 | - name: start the nginx service 55 | service: name=nginx state=started enabled=yes 56 | 57 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/templates/default.conf.j2: -------------------------------------------------------------------------------- 1 | #{{ ansible_managed }} 2 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/templates/default.j2: -------------------------------------------------------------------------------- 1 | #{{ ansible_managed }} 2 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/templates/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | #{{ ansible_managed }} 2 | {% if ansible_os_family == 'RedHat' %} 3 | user nginx; 4 | {% endif %} 5 | {% if ansible_os_family == 'Debian' %} 6 | user www-data; 7 | {% endif %} 8 | 9 | worker_processes {{ ansible_processor_count }}; 10 | pid /var/run/nginx.pid; 11 | 12 | 13 | events { 14 | worker_connections {{ nginx_max_clients }}; 15 | } 16 | 17 | 18 | http { 19 | 20 | include /etc/nginx/mime.types; 21 | default_type application/octet-stream; 22 | 23 | access_log {{ nginx_log_dir}}/{{ nginx_access_log_name}}; 24 | error_log {{ nginx_log_dir}}/{{ nginx_error_log_name}}; 25 | 26 | {% for k,v in nginx_http_params.iteritems() %} 27 | {{ k }} {{ v }}; 28 | {% endfor %} 29 | 30 | gzip on; 31 | gzip_disable "msie6"; 32 | 33 | include /etc/nginx/conf.d/*.conf; 34 | include /etc/nginx/sites-enabled/*; 35 | } 36 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/templates/site.j2: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | {% if nginx_separete_logs_per_site == True %} 4 | access_log {{ nginx_log_dir}}/{{ item.server.server_name}}-{{ nginx_access_log_name}}; 5 | error_log {{ nginx_log_dir}}/{{ item.server.server_name}}-{{ nginx_error_log_name}}; 6 | {% endif %} 7 | 8 | {% for k,v in item.server.iteritems() %} 9 | {% if k.find('location') == -1 and k != 'file_name' %} 10 | {{ k }} {{ v }}; 11 | {% endif %} 12 | {% endfor %} 13 | 14 | {% for k,v in item.server.iteritems() if k.find('location') != -1 %} 15 | location {{ v.name }} { 16 | {% for x,y in v.iteritems() if x != 'name' %} 17 | {{ x }} {{ y }}; 18 | {% endfor %} 19 | } 20 | {% endfor %} 21 | } 22 | 23 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/nginx/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | env: 4 | RUNLEVEL: 1 5 | 6 | redhat_pkg: 7 | - nginx 8 | 9 | ubuntu_pkg: 10 | - python-selinux 11 | - nginx 12 | 13 | 14 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/.gitignore: -------------------------------------------------------------------------------- 1 | vagrant* 2 | .vagrant 3 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/README.md: -------------------------------------------------------------------------------- 1 | ntp 2 | === 3 | 4 | [![Build Status](https://travis-ci.org/resmo/ansible-role-ntp.png?branch=master)](https://travis-ci.org/resmo/ansible-role-ntp) 5 | 6 | This role enables users to install and configure ntp on their hosts. 7 | 8 | Requirements 9 | ------------ 10 | 11 | This role requires Ansible 1.4 or higher, and platform requirements are listed 12 | in the metadata file. 13 | 14 | Examples 15 | -------- 16 | 17 | 1) Install ntp and set the default settings. 18 | 19 | - hosts: all 20 | roles: 21 | - role: ntp 22 | 23 | 2) Install ntp and set some custom servers. 24 | 25 | - hosts: all 26 | roles: 27 | - role: ntp 28 | ntp_config_server: [2.ubuntu.pool.ntp.org, 1.ubuntu.pool.ntp.org] 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | - Benno Joy 39 | - René Moser 40 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ntp_pkg_state: 'installed' 3 | ntp_service_state: 'started' 4 | ntp_service_enabled: 'yes' 5 | 6 | ntp_config_server: [ '0.pool.ntp.org', '1.pool.ntp.org', '2.pool.ntp.org', '3.pool.ntp.org' ] 7 | ntp_config_restrict: 8 | - '-4 default kod notrap nomodify nopeer noquery' 9 | - '-6 default kod notrap nomodify nopeer noquery' 10 | - '127.0.0.1' 11 | - '::1' 12 | 13 | ntp_config_listen: 14 | - '127.0.0.1' 15 | 16 | ntp_config_filegen: 17 | - 'loopstats file loopstats type day enable' 18 | - 'peerstats file peerstats type day enable' 19 | - 'clockstats file clockstats type day enable' 20 | 21 | ntp_config_statistics: 'loopstats peerstats clockstats' 22 | ntp_config_crypto: '' 23 | ntp_config_includefile: '' 24 | ntp_config_keys: '' 25 | ntp_config_trustedkey: '' 26 | ntp_config_requestkey: '' 27 | ntp_config_controlkey: '' 28 | ntp_config_broadcast: '' 29 | ntp_config_broadcastclient: '' 30 | ntp_config_multicastclient: '' 31 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart ntp 3 | service: name={{ ntp_service_name }} state=restarted 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "René Moser" 4 | license: BSD 5 | min_ansible_version: 1.4 6 | platforms: 7 | - name: EL 8 | versions: 9 | - 5 10 | - 6 11 | - name: Fedora 12 | versions: 13 | - 16 14 | - 17 15 | - 18 16 | - name: Ubuntu 17 | versions: 18 | - precise 19 | - quantal 20 | - raring 21 | - saucy 22 | - name: Debian 23 | versions: 24 | - wheezy 25 | categories: 26 | - system 27 | dependencies: [] 28 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add the OS specific variables 3 | include_vars: '{{ ansible_os_family }}.yml' 4 | tags: [ 'configuration', 'package', 'service', 'ntp' ] 5 | 6 | - name: Install the required packages in Redhat derivatives 7 | yum: name=ntp state={{ ntp_pkg_state }} 8 | when: ansible_os_family == 'RedHat' 9 | tags: [ 'package', 'ntp' ] 10 | 11 | - name: Install the required packages in Debian derivatives 12 | apt: name=ntp state={{ ntp_pkg_state }} 13 | when: ansible_os_family == 'Debian' 14 | tags: [ 'package', 'ntp' ] 15 | 16 | - name: Copy the ntp.conf template file 17 | template: src=ntp.conf.j2 dest=/etc/ntp.conf 18 | notify: 19 | - restart ntp 20 | tags: [ 'configuration', 'package', 'ntp' ] 21 | 22 | - name: Start/stop ntp service 23 | service: name={{ ntp_service_name }} state={{ ntp_service_state }} enabled={{ ntp_service_enabled }} pattern='/ntpd' 24 | tags: [ 'service', 'ntp' ] 25 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/templates/ntp.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | 3 | driftfile {{ ntp_config_driftfile }} 4 | 5 | {% for server in ntp_config_server %} 6 | server {{ server }} 7 | {% endfor %} 8 | 9 | {% if ntp_config_statistics %} 10 | statistics {{ ntp_config_statistics }} 11 | {% endif %} 12 | 13 | {% for filegen in ntp_config_filegen %} 14 | filegen {{ filegen }} 15 | {% endfor %} 16 | 17 | {% for listen in ntp_config_listen %} 18 | interface listen {{ listen }} 19 | {% endfor %} 20 | 21 | {% for restrict in ntp_config_restrict %} 22 | restrict {{ restrict }} 23 | {% endfor %} 24 | 25 | {% if ntp_config_crypto %} 26 | crypto 27 | {% endif %} 28 | 29 | {% if ntp_config_includefile %} 30 | includefile {{ ntp_config_includefile }} 31 | {% endif %} 32 | 33 | {% if ntp_config_keys %} 34 | keys {{ ntp_config_keys }} 35 | {% endif %} 36 | 37 | {% if ntp_config_trustedkey %} 38 | trustedkey {{ ntp_config_trustedkey }} 39 | {% endif %} 40 | 41 | {% if ntp_config_requestkey %} 42 | requestkey {{ ntp_config_requestkey }} 43 | {% endif %} 44 | 45 | {% if ntp_config_controlkey %} 46 | controlkey {{ ntp_config_controlkey }} 47 | {% endif %} 48 | 49 | {% if ntp_config_broadcast %} 50 | broadcast {{ ntp_config_broadcast }} 51 | {% endif %} 52 | 53 | {% if ntp_config_broadcastclient %} 54 | broadcastclient 55 | {% endif %} 56 | 57 | {% if ntp_config_multicastclient %} 58 | multicastclient {{ ntp_config_multicastclient }} 59 | {% endif %} 60 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/tests/role.yml: -------------------------------------------------------------------------------- 1 | - hosts: localhost 2 | roles: 3 | - ansible-role-ntp 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/vars/Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ntp_service_name: ntp 3 | ntp_config_driftfile: /var/lib/ntp/ntp.drift 4 | 5 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/ntp/vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ntp_service_name: ntpd 3 | ntp_config_driftfile: /var/lib/ntp/drift 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/README.md: -------------------------------------------------------------------------------- 1 | redis 2 | ===== 3 | 4 | This role helps to deploy a Redis master or replication server on target host. 5 | This roles sets several default values for Redis configuration which can be 6 | overrriden by the user. 7 | 8 | Requirements 9 | ------------ 10 | 11 | This role requires Ansible 1.4 or higher, and platform requirements are listed 12 | in the metadata file. 13 | 14 | Role Variables 15 | -------------- 16 | 17 | The variables that can be passed to this role and a brief description about 18 | them are as follows. See the documentation for Redis for details: 19 | 20 | redis_bind_address # The network address for redis to bind to 21 | redis_port: 6379 # Port for redis server 22 | redis_syslog_enabled: "yes" # enable_syslog 23 | redis_databases: 16 # Set number of databases 24 | redis_database_save_times: # Save the DB on disk (seconds changes) 25 | - [900, 1] 26 | - [300, 10] 27 | - [60, 10000] 28 | redis_dbfilename: dump.rdb # Filename for the db 29 | redis_db_dir: /var/lib/redis # DB directory 30 | redis_role: master # The role for this redis deployment (master/slave) 31 | redis_requirepass: false # If password is required for querying 32 | redis_pass: None # Password if require_pass is enabled 33 | redis_max_clients: 128 34 | redis_max_memory: 512mb 35 | redis_maxmemory_policy: volatile-lru 36 | redis_appendfsync: everysec # How often to sync the filesystem 37 | 38 | # If redis_role is "slave", set these values too 39 | redis_master_ip: 1.1.1.1 # The master's IP 40 | redis_master_port: 6379 # master port 41 | redis_master_auth: None # master auth 42 | 43 | Examples 44 | -------- 45 | 46 | The following example sets up a master Redis server. 47 | 48 | - hosts: all 49 | sudo: true 50 | roles: 51 | - {role: bennojoy.redis, redis_port: 11244} 52 | 53 | The following example sets up a slave Redis server. 54 | 55 | - hosts: all 56 | sudo: true 57 | roles: 58 | - {role: bennojoy.redis, 59 | redis_role: 'slave', 60 | master_ip: '192.168.2.10', 61 | master_auth: 'foobar'} 62 | 63 | 64 | Dependencies 65 | ------------ 66 | 67 | None 68 | 69 | License 70 | ------- 71 | 72 | BSD 73 | 74 | Author Information 75 | ------------------ 76 | 77 | Benno Joy 78 | 79 | 80 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | redis_bind_address: "0.0.0.0" 4 | redis_port: 6379 5 | redis_syslog_enabled: "yes" 6 | # Must be USER or between LOCAL0-LOCAL7. 7 | redis_syslog_facility: "local0" 8 | redis_logfile: /var/log/redis.log 9 | redis_databases: 16 10 | redis_database_save_times: 11 | - [900, 1] 12 | - [300, 10] 13 | - [60, 10000] 14 | redis_dbfilename: dump.rdb 15 | redis_db_dir: /var/lib/redis 16 | redis_role: master 17 | redis_requirepass: false 18 | redis_pass: None 19 | redis_max_clients: 128 20 | redis_max_memory: 512mb 21 | redis_maxmemory_policy: volatile-lru 22 | redis_appendfsync: everysec 23 | # check https://www.kernel.org/doc/Documentation/sysctl/vm.txt 24 | # and http://redis.io/topics/faq 25 | redis_overcommit_memory: 1 26 | #If role is slave set these values too 27 | redis_master_ip: 1.1.1.1 28 | redis_master_port: 6379 29 | redis_master_auth: None 30 | 31 | 32 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/files/epel6.repo: -------------------------------------------------------------------------------- 1 | [epel] 2 | name=Extra Packages for Enterprise Linux 6 - $basearch 3 | baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch 4 | #mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch 5 | failovermethod=priority 6 | enabled=1 7 | gpgcheck=1 8 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 9 | 10 | [epel-debuginfo] 11 | name=Extra Packages for Enterprise Linux 6 - $basearch - Debug 12 | #baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch/debug 13 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch 14 | failovermethod=priority 15 | enabled=0 16 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 17 | gpgcheck=1 18 | 19 | [epel-source] 20 | name=Extra Packages for Enterprise Linux 6 - $basearch - Source 21 | #baseurl=http://download.fedoraproject.org/pub/epel/6/SRPMS 22 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-6&arch=$basearch 23 | failovermethod=priority 24 | enabled=0 25 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6 26 | gpgcheck=1 27 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/files/epel7.repo: -------------------------------------------------------------------------------- 1 | [epel] 2 | name=Extra Packages for Enterprise Linux 7 - $basearch 3 | #baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch 4 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch 5 | failovermethod=priority 6 | enabled=1 7 | gpgcheck=0 8 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 9 | 10 | [epel-debuginfo] 11 | name=Extra Packages for Enterprise Linux 7 - $basearch - Debug 12 | #baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch/debug 13 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch 14 | failovermethod=priority 15 | enabled=0 16 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 17 | gpgcheck=1 18 | 19 | [epel-source] 20 | name=Extra Packages for Enterprise Linux 7 - $basearch - Source 21 | #baseurl=http://download.fedoraproject.org/pub/epel/7/SRPMS 22 | mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=$basearch 23 | failovermethod=priority 24 | enabled=0 25 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 26 | gpgcheck=1 27 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: restart redis 3 | service: name={{ redis_service }} state=restarted 4 | 5 | - name: restart rsyslog 6 | service: name=rsyslog state=restarted 7 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "Benno Joy" 4 | company: AnsibleWorks 5 | license: BSD 6 | min_ansible_version: 1.4 7 | platforms: 8 | - name: EL 9 | versions: 10 | - 6 11 | - 7 12 | - name: Fedora 13 | versions: 14 | - 19 15 | - 20 16 | - 21 17 | - rawhide 18 | - name: Ubuntu 19 | versions: 20 | - precise 21 | - quantal 22 | - raring 23 | - saucy 24 | categories: 25 | - web 26 | dependencies: [] 27 | 28 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Add the OS specific varibles 4 | include_vars: "{{ ansible_os_family }}.yml" 5 | 6 | - name: Install the epel packages 7 | yum: name=http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm state=present 8 | when: ansible_os_family == "RedHat" and ansible_distribution != "Fedora" 9 | and ansible_distribution_major_version == "6" 10 | 11 | - name: Install the epel packages 12 | yum: name=http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-1.noarch.rpm state=present 13 | when: ansible_os_family == "RedHat" and ansible_distribution != "Fedora" 14 | and ansible_distribution_major_version == "7" 15 | 16 | - name: Install the Redis packages 17 | yum: name={{ item }} state=present 18 | with_items: redis_redhat_pkg 19 | when: ansible_os_family == "RedHat" 20 | 21 | - name: Install the Redis packages 22 | apt: name={{ item }} state=present update_cache=yes 23 | with_items: redis_ubuntu_pkg 24 | environment: env 25 | when: ansible_os_family == "Debian" 26 | 27 | - name: Copy the redis configuration file 28 | template: src=redis.conf.j2 dest={{ redis_conf_dest }} 29 | notify: 30 | - restart redis 31 | 32 | - name: Copy the rsyslogd configuration file for redis filter 33 | template: src=rsyslogd.conf.j2 dest=/etc/rsyslog.d/redis.conf 34 | when: redis_syslog_enabled == "yes" 35 | notify: 36 | - restart rsyslog 37 | 38 | - name: Set the kernel paramter for vm overcommit 39 | sysctl: name=vm.overcommit_memory value={{ redis_overcommit_memory }} state=present 40 | 41 | - name: start the redis service 42 | service: name={{ redis_service }} state=started enabled=yes 43 | 44 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/templates/rsyslogd.conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | if $programname == 'redis' then {{ redis_logfile }} 3 | & ~ 4 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/vars/Debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | redis_service: redis-server 4 | redis_conf_dest: /etc/redis/redis.conf 5 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | redis_service: redis 2 | redis_conf_dest: /etc/redis.conf 3 | -------------------------------------------------------------------------------- /dummy-ansible-files/roles/redis/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | env: 4 | RUNLEVEL: 1 5 | 6 | redis_redhat_pkg: 7 | - libselinux-python 8 | - redis 9 | 10 | redis_ubuntu_pkg: 11 | - python-selinux 12 | - redis-server 13 | 14 | 15 | -------------------------------------------------------------------------------- /dummy-ansible-files/sample-playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: local 3 | gather_facts: no 4 | remote_user: root 5 | tasks: 6 | - name: test connection 7 | debug: msg="yeah its running" 8 | delegate_to: 127.0.0.1 9 | 10 | - name: get url 11 | get_url: url="http://www.ozarkia.net/bill/anarchism/rants/NetNeutrality.txt" dest="/tmp/net-neutrality.txt" 12 | delegate_to: 127.0.0.1 13 | -------------------------------------------------------------------------------- /goansible/log_analyzer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "regexp" 9 | ) 10 | 11 | var ( 12 | mainlogPattern = createPattern(`^(PLAY|TASK\:|FATAL\:|ok\:|changed\:|failed\:)`) 13 | playPattern = createPattern(`^PLAY\s*\[*([a-zA-Z0-9]*)\]*`) 14 | taskPattern = createPattern(`^TASK\:\s*\[\s*([^|\]]*)\s*|\s*([^|\]]*)\s*\]`) 15 | fatalPattern = createPattern(`^FATAL:\s*(.*)`) 16 | statusPattern = createPattern(`^(ok|changed|failed):\s*\[([^\]]*)\](.*)`) 17 | statusDetailPattern = createPattern(`\s*=>\s*(.*)\s*`) //gives out json with task status detail for that node 18 | ) 19 | 20 | func createPattern(pattern string) *regexp.Regexp { 21 | regex, err := regexp.Compile(pattern) 22 | if err != nil { 23 | panic("There was a problem with the regular expression.") 24 | } 25 | return regex 26 | } 27 | 28 | func lineToDetails(line, line_type string) { 29 | switch line_type { 30 | case "PLAY": 31 | playbook := playPattern.FindStringSubmatch(line) 32 | fmt.Printf("PLAYBOOK: %q\n", playbook[1]) 33 | case "TASK:": 34 | task := taskPattern.FindStringSubmatch(line) 35 | fmt.Printf("TASK: %q\n", task[1]) 36 | case "FATAL:": 37 | fatal := fatalPattern.FindStringSubmatch(line) 38 | fmt.Printf("FATAL: %q\n", fatal[1]) 39 | case "ok:", "changed:", "failed:": 40 | status := statusPattern.FindStringSubmatch(line) 41 | var statusDetail string 42 | if statusDetailPattern.MatchString(status[3]) { 43 | statusDetail = statusDetailPattern.FindStringSubmatch(status[3])[1] 44 | } 45 | updateStatus(status[1], status[2], statusDetail) 46 | } 47 | } 48 | 49 | func updateStatus(status, node, detail string) { 50 | switch status { 51 | case "ok": 52 | fmt.Printf("%s is ok:\n%s\n", node, detail) 53 | case "changed": 54 | fmt.Printf("%s is changed:\n%s\n", node, detail) 55 | case "failed": 56 | fmt.Printf("%s is failed:\n%s\n", node, detail) 57 | } 58 | } 59 | 60 | func grep(regex *regexp.Regexp, filename string) { 61 | fh, err := os.Open(filename) 62 | f := bufio.NewReader(fh) 63 | 64 | if err != nil { 65 | fmt.Println("ERROR: There was a problem opening the file.") 66 | return 67 | } 68 | defer fh.Close() 69 | 70 | buf := make([]byte, 1024) 71 | for { 72 | buf, _, err = f.ReadLine() 73 | if err != nil { 74 | return 75 | } 76 | 77 | line := string(buf) 78 | match_line := regex.FindStringSubmatch((line)) 79 | if len(match_line) > 0 { 80 | lineToDetails(line, match_line[1]) 81 | } 82 | } 83 | } 84 | 85 | func main() { 86 | flag.Parse() 87 | if flag.NArg() == 1 { 88 | logfile := flag.Arg(0) 89 | grep(mainlogPattern, logfile) 90 | } else { 91 | fmt.Printf("Wrong number of arguments.\n") 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /screenshots/dashboard.failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/dashboard.failed.png -------------------------------------------------------------------------------- /screenshots/dashboard.passed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/dashboard.passed.png -------------------------------------------------------------------------------- /screenshots/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/dashboard.png -------------------------------------------------------------------------------- /screenshots/dashboard.searched.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/dashboard.searched.png -------------------------------------------------------------------------------- /screenshots/homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/homepage.png -------------------------------------------------------------------------------- /screenshots/hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/hosts.png -------------------------------------------------------------------------------- /screenshots/playbooks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/playbooks.png -------------------------------------------------------------------------------- /screenshots/roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/screenshots/roles.png -------------------------------------------------------------------------------- /www-data/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |
146 |

Take a deep breath and goto Homepage, start your joruney with a fresh mind and high hopes... you might reach where you were planning to land.

147 |
148 |

It looks like this was the result of either:

149 |
    150 |
  • a mistyped address
  • 151 |
  • an out-of-date link
  • 152 |
153 |
154 |
155 | Think it should have been there, raise an issue with 156 |

dashr@github

157 |
158 | 159 | 160 | -------------------------------------------------------------------------------- /www-data/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.1.0 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#555;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /www-data/css/main.css: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Author's custom styles 3 | ========================================================================== */ 4 | 5 | .task-detail { 6 | display: none; 7 | } 8 | -------------------------------------------------------------------------------- /www-data/dashboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ansible Dashr - 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 |
33 | 45 |
46 |
47 | 48 | 53 |
54 |
55 | 56 | 57 |
58 |       59 |       60 | 61 |
62 | 63 |
    64 | 65 |
      66 | 67 |
      68 |
      69 | 70 | 73 |
      74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /www-data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/www-data/favicon.ico -------------------------------------------------------------------------------- /www-data/hosts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ansible Dashr - 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 |
      33 | 45 |
      46 |
      47 |

      Inventories

      48 | 49 | 50 |
      51 | 52 |
      53 |

      HostGroups

      54 | 55 | 56 |
      57 | 58 |
      59 |

      {{HostName}}

      60 | 61 |
      62 |
      Group:
      63 |
      {{Group}}
      64 |
      65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
      Attributes inferenced from Inventory and Group/Host Vars
      KeyValue
      {{FacterXYZ}}{{FacterXYZ_Value}}
      80 |
      81 | 82 |
      83 | 84 | 87 |
      88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /www-data/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # TEAM 5 | 6 | abhishekkr -- OpenChaos -- @abionic 7 | 8 | # THANKS 9 | 10 | All FOSS contributors and supporters. 11 | 12 | # TECHNOLOGY COLOPHON 13 | 14 | HTML5, CSS3 15 | jQuery, Modernizr 16 | -------------------------------------------------------------------------------- /www-data/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/www-data/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /www-data/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abhishekkr/ansible-dashr/287cf6f809dbd6ad9eaed0d56f880837ced7103f/www-data/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /www-data/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ansible Dashr - 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 |
      33 | 45 |
      46 | 69 | 70 | 71 |
      72 | 73 | 76 |
      77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /www-data/js/home.js: -------------------------------------------------------------------------------- 1 | 2 | function pie_chart(obj, values, title){ 3 | obj.highcharts({ 4 | chart: { 5 | plotBackgroundColor: null, 6 | plotBorderWidth: null, 7 | plotShadow: false 8 | }, 9 | title: { text: "Summary of " + title }, 10 | tooltip: { 11 | pointFormat: '{series.name}: {point.percentage:.1f}%' 12 | }, 13 | plotOptions: { 14 | pie: { 15 | allowPointSelect: true, 16 | cursor: 'pointer', 17 | dataLabels: { 18 | enabled: true, 19 | format: '{point.name}: {point.percentage:.1f} %', 20 | style: { 21 | color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black' 22 | } 23 | } 24 | } 25 | }, 26 | series: [{ type: 'pie', name: title, data: values }] 27 | }); 28 | } 29 | 30 | function half_pie(obj, values, title){ 31 | obj.highcharts({ 32 | chart: { 33 | plotBackgroundColor: null, 34 | plotBorderWidth: 0, 35 | plotShadow: false 36 | }, 37 | title: { 38 | text: 'Ratio of
      ' + title, 39 | align: 'center', 40 | verticalAlign: 'middle', 41 | y: 50 42 | }, 43 | tooltip: { 44 | pointFormat: '{series.name}: {point.percentage:.1f}%' 45 | }, 46 | plotOptions: { 47 | pie: { 48 | dataLabels: { 49 | enabled: true, 50 | distance: -50, 51 | style: { fontWeight: 'bold', color: 'white', textShadow: '0px 1px 2px black' } 52 | }, 53 | startAngle: -90, 54 | endAngle: 90, 55 | center: ['50%', '75%'] 56 | } 57 | }, 58 | series: [{ 59 | type: 'pie', 60 | name: title, 61 | innerSize: '50%', 62 | data: values 63 | }] 64 | }); 65 | } 66 | 67 | 68 | $(function () { 69 | var pie_data = [], hosts_info = {}; 70 | 71 | var host_list = parseHostList(dashr_log_hostlist); 72 | for(var idx in host_list){ 73 | var host_yaml_uri = decodeURIComponent(dashr_log_directory + "/" + host_list[idx]); 74 | hosts_info[host_list[idx]] = YAMLURI2JSON(host_yaml_uri); 75 | } 76 | 77 | var state_count = calculateTaskStats(hosts_info); 78 | for(var _type in state_count){ 79 | pie_data.push([_type, state_count[_type]]); 80 | } 81 | 82 | pie_chart($('#run_stats'), pie_data, 'Ansible Run Status') 83 | 84 | 85 | var detailed_stats = calculateDetailedTaskStats(hosts_info); 86 | var detailed_stats_data = []; 87 | for(var _type in detailed_stats){ 88 | detailed_stats_data.push([_type, detailed_stats[_type].length]); 89 | } 90 | half_pie($('#peice_stat'), detailed_stats_data, "Ansible Cog") 91 | }); 92 | -------------------------------------------------------------------------------- /www-data/js/main.dashboard.js: -------------------------------------------------------------------------------- 1 | /********* 2 | * Dashboard display specific to Hosts Callback YAML Log File listing 3 | *********/ 4 | var dashr_dashboard = new Object(); 5 | 6 | /* return bootstrap badge class based on state */ 7 | dashr_dashboard.getBadge = function (state){ 8 | switch (state) { 9 | case "unreachable": 10 | case "failed": 11 | return "badge-important"; 12 | case "changed": 13 | case "ok": 14 | return "badge-success"; 15 | default: 16 | console.log("Sorry, we are out of " + state + "."); 17 | return ""; 18 | } 19 | }; 20 | 21 | /* toggle DashbBoard Task Details */ 22 | dashr_dashboard.toggleDashboardTaskDetails = function (self){ 23 | var task_detail_node = self.parentNode; 24 | var task_details = task_detail_node.querySelector(".task-detail"); 25 | var icon = task_detail_node.querySelector(".toggle-icon"); 26 | var msg = task_detail_node.querySelector(".toggle-msg"); 27 | if(icon.classList.contains("icon-plus-sign")){ 28 | icon.classList.remove('icon-plus-sign'); 29 | icon.classList.add('icon-minus-sign'); 30 | task_details.style.display = "block"; 31 | msg.innerHTML = "hide details" 32 | } else { 33 | icon.classList.remove('icon-minus-sign'); 34 | icon.classList.add('icon-plus-sign'); 35 | task_details.style.display = "none"; 36 | msg.innerHTML = "show details" 37 | } 38 | }; 39 | 40 | /* convert passed task details-dict to html */ 41 | dashr_dashboard.taskDetailsToHTML = function (details){ 42 | var _html = "
      show details
      "; 43 | for(var detail_type in details){ 44 | _html += "
      " + detail_type + ":" + details[detail_type] + "
      "; 45 | } 46 | _html += "
      "; 47 | return _html; 48 | }; 49 | 50 | /* boolean return if element is in list */ 51 | dashr_dashboard.isElementInList = function (element, list){ 52 | return list.indexOf(element) >= 0 53 | }; 54 | 55 | /* boolean return if element is not in list */ 56 | dashr_dashboard.isElementNotInList = function (element, list){ 57 | return list.indexOf(element) < 0 58 | }; 59 | 60 | /* entry for a host if got no logs till now */ 61 | dashr_dashboard.ifHostHasNoTasksListed = function (hostname){ 62 | var entry = { 63 | "hostname": hostname, 64 | "taskstate": "", 65 | "taskdetails": "" 66 | }; 67 | if(dashr_dashboard.isElementInList("failed", dashr_dashboard.state_type)){ 68 | entry["taskname"] = "Nothing Failed :)"; 69 | } else if(dashr_dashboard.isElementInList("ok", dashr_dashboard.state_type)){ 70 | entry["taskname"] = "Nothing Passed :("; 71 | } else { 72 | entry["taskname"] = "Run Something :/"; 73 | } 74 | return entry; 75 | }; 76 | 77 | /* updating dashboard list for a given host details */ 78 | dashr_dashboard.get_host_info = function (hostname, host_info_list, state_type){ 79 | if(host_info_list.length == 0){ 80 | dashr_dashboard.listjs.add(hostname, dashr_dashboard.ifHostHasNoTasksListed(hostname)); 81 | return 82 | } 83 | for(var info_idx in host_info_list){ 84 | var _state = host_info_list[info_idx]['state']; 85 | dashr_dashboard.taskstate_counter = updateStateCounter(dashr_dashboard.taskstate_counter, _state); 86 | if(state_type != "all" && dashr_dashboard.isElementNotInList(_state, state_type)){ 87 | continue; 88 | } 89 | dashr_dashboard.listjs.add( 90 | { 91 | "hostname": hostname, 92 | "taskname": host_info_list[info_idx]['name'], 93 | "taskstate": "" + _state + "", 94 | "taskdetails": dashr_dashboard.taskDetailsToHTML(host_info_list[info_idx]['details']), 95 | } 96 | ) ; 97 | } 98 | }; 99 | 100 | /* manage update of dashboard for all hosts for given state */ 101 | dashr_dashboard.get_dashboard_values = function (callback_dir, state_type){ 102 | // update hosts_info 103 | for(var host_idx in dashr_dashboard.host_list){ 104 | var host_yaml_uri = decodeURIComponent(callback_dir + "/" + dashr_dashboard.host_list[host_idx]); 105 | var host_info_list = YAMLURI2JSON(host_yaml_uri); 106 | dashr_dashboard.get_host_info(dashr_dashboard.host_list[host_idx], host_info_list, state_type); 107 | } 108 | }; 109 | 110 | /* update task state counter on side-navs */ 111 | dashr_dashboard.update_task_counter = function(){ 112 | document.querySelector("#AllCount").innerHTML = " (" + (dashr_dashboard.taskstate_counter["Passed"] + dashr_dashboard.taskstate_counter["Failed"]) + " Tasks)"; 113 | document.querySelector("#PassedCount").innerHTML = " (" + (dashr_dashboard.taskstate_counter["Passed"]) + " Tasks)"; 114 | document.querySelector("#FailedCount").innerHTML = " (" + (dashr_dashboard.taskstate_counter["Failed"]) + " Tasks)"; 115 | }; 116 | 117 | /* assign onclick action to All, Passed, Failed */ 118 | dashr_dashboard.submenu_events = function(){ 119 | document.querySelector("#All").onclick = function(){ 120 | dashr_dashboard.listjs.clear(); 121 | dashr_dashboard.get_dashboard_values(dashr_log_directory, ["all"]); 122 | }; 123 | document.querySelector("#Passed").onclick = function(){ 124 | dashr_dashboard.listjs.clear(); 125 | dashr_dashboard.get_dashboard_values(dashr_log_directory, ["ok", "changed"]); 126 | }; 127 | document.querySelector("#Failed").onclick = function(){ 128 | dashr_dashboard.listjs.clear(); 129 | dashr_dashboard.get_dashboard_values(dashr_log_directory, ["failed", "unreachable", "error"]); 130 | }; 131 | }; 132 | 133 | /* getParameters to initiate parameters used (and passed) as HTTP Request Variables */ 134 | dashr_dashboard.getParameters = function(){ 135 | dashr_dashboard.state_type = ["all"]; 136 | dashr_dashboard.host_list = parseHostList(dashr_log_hostlist); 137 | 138 | var get_vars = getUrlVars() 139 | if (get_vars.hasOwnProperty("state")) { 140 | dashr_dashboard.state_type = get_vars["state"].split(","); 141 | } 142 | if (get_vars.hasOwnProperty("host")) { 143 | var q_host = decodeURIComponent(get_vars["host"]); 144 | dashr_dashboard.host_list = [q_host]; 145 | } 146 | }; 147 | 148 | /* listjs preparations */ 149 | dashr_dashboard.listjs_init = function(){ 150 | var dashboard_options = { 151 | valueNames: [ 'hostname', 'taskname', 'taskstate', 'taskdetails' ], 152 | item: '
    • Host:
      Task:
      State:

    • ', 153 | page: 7, 154 | plugins: [ ListPagination({}) ] 155 | }; 156 | dashr_dashboard.listjs = new List('callbackDetails', dashboard_options); 157 | }; 158 | 159 | /*********************** main() ******************* 160 | require following variable pre-defined via dashr-created config/js/main-data.js: 161 | * dashr_log_directory : path where all host callback log yamls will get generated 162 | * dashr_log_hostlist : path to yaml of host list resulting on callback 163 | **************************************************/ 164 | 165 | dashr_dashboard.listjs_init(); 166 | dashr_dashboard.getParameters(); 167 | dashr_dashboard.taskstate_counter = {"Passed":0, "Failed":0}; 168 | 169 | dashr_dashboard.submenu_events(); 170 | 171 | dashr_dashboard.get_dashboard_values(dashr_log_directory, dashr_dashboard.state_type); 172 | 173 | dashr_dashboard.update_task_counter(dashr_dashboard.taskstate_counter); 174 | -------------------------------------------------------------------------------- /www-data/js/main.hosts.js: -------------------------------------------------------------------------------- 1 | /********* 2 | * specific to Hosts Inventory File listing 3 | *********/ 4 | 5 | /*** populate inventory-bar for all inventory list ***/ 6 | function UpdateInventoryList(inventory_list){ 7 | var inventories = document.querySelector('#inventories'); 8 | 9 | var inventoryHTML = "

      Inventories

      "; 15 | inventories.innerHTML = inventoryHTML; 16 | UpdateHostGroupList(document.querySelector('.inventoryEntry').id); 17 | } 18 | 19 | /*** populating host-bar for first or required invenotry ***/ 20 | function UpdateHostGroupList(inventory){ 21 | var hosts = document.querySelector('#hostgroups'); 22 | 23 | var hostsHTML = "

      " + inventory + "

      "; 24 | for(var _group in hostINI[inventory]){ 25 | hostsHTML += "
      "; 26 | hostsHTML += "

      " + _group + "

      "; 27 | hostsHTML += " "; 33 | hostsHTML += "

      "; 34 | } 35 | hosts.innerHTML = hostsHTML; 36 | UpdateHostDetails(document.querySelector('.hostEntry').id); 37 | } 38 | 39 | /*** populate host-detail field ***/ 40 | function UpdateHostDetails(hostname){ 41 | var hostname_id = hostname.replace(/\./g, "\\.") 42 | var hostdetails = document.querySelector('#hostdetails'); 43 | 44 | var group_element = document.querySelector('#' + hostname_id).parentNode.parentNode.querySelector("h4"); 45 | var group_name = group_element.innerHTML; 46 | var inventory = group_element.parentNode.parentNode.querySelector("h3").innerHTML; 47 | var inventory_file_details = hostINI[inventory][group_name][hostname]; 48 | 49 | hostdetails.querySelector("#hostname").innerHTML = hostname; 50 | 51 | var hostsDLHTML = "
      Group:
      " + group_name + "
      "; 52 | for(var _key in inventory_file_details){ 53 | hostsDLHTML += "
      " + _key + ":
      " + inventory_file_details[_key] + "
      "; 54 | } 55 | hostdetails.querySelector("dl").innerHTML = hostsDLHTML; 56 | hostdetails.querySelector("#host_details_keyval").innerHTML = UpdateHostDetailsByVars(hostname, group_name, inventory); 57 | } 58 | 59 | /*** update GroupVars applicable to Hostname ***/ 60 | function UpdateHostDetailsByVars(hostname, group_name, inventory){ 61 | var host_vars = VarYAMLAsJSON(host_vars_www_path + "/" + hostname); 62 | host_vars = VarsUpdatedFromGroup(inventory, group_name, host_vars) 63 | var all_vars = VarYAMLAsJSON(group_vars_www_path + "/all"); 64 | for(var _k in all_vars){ 65 | if(! host_vars.hasOwnProperty(_k)){ 66 | host_vars[_k] = all_vars[_k]; 67 | } 68 | } 69 | 70 | var hostsGroupVarHTML = ""; 71 | for(var _key in host_vars){ 72 | var _host_vars_html = JSON.stringify(host_vars[_key]).replace(/\{\{/g, "{{").replace(/\}\}/g, "}}"); 73 | hostsGroupVarHTML += "" + _key + ":" + _host_vars_html + "" 74 | } 75 | return hostsGroupVarHTML; 76 | } 77 | 78 | /*** return group_updated Var appended not overrideen ***/ 79 | function VarsUpdatedFromGroup(inventory, group_name, var_dict){ 80 | var group_vars = VarYAMLAsJSON(group_vars_www_path + "/" + group_name); 81 | for(var _k in group_vars){ 82 | if(! var_dict.hasOwnProperty(_k)){ 83 | var_dict[_k] = group_vars[_k]; 84 | } 85 | } 86 | for(var _group in hostINI[inventory]){ 87 | for(var _host in hostINI[inventory][_group]){ 88 | if(_host == group_name){ 89 | var_dict = VarsUpdatedFromGroup(inventory, _group, var_dict); 90 | break; 91 | } 92 | } 93 | } 94 | return var_dict; 95 | } 96 | 97 | /*** fetch var yaml as json ***/ 98 | function VarYAMLAsJSON(var_path){ 99 | var child = new RegExp("^(.*):children$"); 100 | if(child.test(var_path) == true) { 101 | var_path = child.exec(var_path)[1]; 102 | } 103 | 104 | var group_vars_filedata = loadURI(var_path); 105 | if (group_vars_filedata == "") {return {};} 106 | // replacing only {|} which are not in quotes 107 | group_vars_filedata = group_vars_filedata.replace(/(\{\{)(?=(?:(?:[^"]*"){2})*[^"]*$)/g, "\\{\\{").replace(/(\}\})(?=(?:(?:[^"]*"){2})*[^"]*$)/g, "\\}\\}"); 108 | return jsyaml.load(group_vars_filedata); 109 | } 110 | 111 | /*** main() ***/ 112 | var hostINI = []; 113 | for(var idx in inventories){ 114 | var hostINIConf = loadURI(inventories_www_path + "/" + inventories[idx]); 115 | hostINI[inventories[idx]] = parseINIHiera(hostINIConf); 116 | } 117 | UpdateInventoryList(inventories) 118 | -------------------------------------------------------------------------------- /www-data/js/main.js: -------------------------------------------------------------------------------- 1 | /********** 2 | j-ini-minified 3 | **********/ 4 | var INIRegex={section:/^\s*\[\s*([^\]]*)\s*\]\s*$/,trueParam:/^\s*([\w\.\-\_]+)\s*$/,param:/^\s*([\w\.\-\_]+)\s*=\s*(.*?)\s*$/,comment:/^\s*;.*$/};function populateValueWithToken(c,a,b){if(c.hasOwnProperty("section")){if(c.hasOwnProperty("trueParam")){c.value[c.section][c.trueParam][a]=b}else{c.value[c.section][a]=b}}else{if(c.hasOwnProperty("trueParam")){c.value[c.trueParam][a]=b}else{c.value[a]=b}}}function parseINIToken(c,b){if(INIRegex.trueParam.test(b)){var a=b.match(INIRegex.trueParam);if(c.hasOwnProperty("section")){c.value[c.section][a[1]]={}}else{c.value[a[1]]={}}c.trueParam=a[1]}else{if(INIRegex.param.test(b)){var a=b.match(INIRegex.param);populateValueWithToken(c,a[1],a[2])}}}function parseINILine(e,a){if(INIRegex.comment.test(a)){return}else{if(INIRegex.section.test(a)){var b=a.match(INIRegex.section);e.value[b[1]]={};e.section=b[1]}else{if(a.length==0&&e.hasOwnProperty("section")){delete e.section}else{var d=a.split(/\s+/);for(var c in d){parseINIToken(e,d[c])}delete e.trueParam}}}}function parseINI(c){var d={value:{}};var a=c.split(/\r\n|\r|\n/);for(var b in a){parseINILine(d,a[b])}return d.value}function updateINIChildren(e,a,c){for(var d in e.value[a][c]){if(e.value[c].hasOwnProperty(d)){continue}_default_child_attrib=e.value[a][c][d];for(var b in e.value[c]){e.value[c][b][d]=_default_child_attrib}}}function updateINIParents(c,a){for(var b in c.value){if(a==b){continue}if(typeof(c.value[b])=="string"){continue}if(Object.keys(c.value[b]).indexOf(a)<0){continue}updateINIChildren(c,b,a);c.value[b][a]=(c.value[a])}}function parseINIHiera(b){var c={value:parseINI(b)};for(var a in c.value){updateINIParents(c,a)}return c.value}; 5 | 6 | /********** 7 | j-minified 8 | **********/ 9 | function loadURI(a){var b=new XMLHttpRequest();b.open("GET",a,false);b.send(); e=parseInt(b.status/100); if(e==4||e==5){return "";}; return b.responseText} 10 | function $DOM(a,b){var c=document.querySelectorAll(a);if(b===undefined){b=0}return c[b]} 11 | function getUrlVars(){var v={}; var p=window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,_k,_v){v[_k]=_v;}); return v;} 12 | 13 | /********** 14 | main() 15 | **********/ 16 | 17 | /* return an index-ed key of a dictionary */ 18 | function indexKeyFromDict(index, dict){ 19 | var count = 0; 20 | for(var _k in dict){ 21 | if(count == index){ return _k } 22 | count += 1; 23 | } 24 | } 25 | 26 | /*converts data from YAML URL to JSON and return it 27 | requirs 'nodeca/js-yaml' */ 28 | var YAMLURI2JSON = function (playbook_uri) { 29 | "use strict"; 30 | var data = loadURI(playbook_uri); 31 | return jsyaml.load(data); 32 | }; 33 | 34 | /* return list of hosts to be covered by provided yaml */ 35 | function parseHostList(hostlist_yaml){ 36 | hostlist_yaml = decodeURIComponent(hostlist_yaml); 37 | return YAMLURI2JSON(hostlist_yaml); 38 | } 39 | 40 | /*calculate task state counter*/ 41 | function updateStateCounter(taskstate_counter, state){ 42 | switch (state) { 43 | case "unreachable": 44 | case "failed": 45 | taskstate_counter["Failed"] += 1; 46 | break; 47 | case "changed": 48 | case "ok": 49 | taskstate_counter["Passed"] += 1; 50 | break; 51 | } 52 | return taskstate_counter; 53 | } 54 | function calculateTaskStats(hosts_info){ 55 | var taskstate_counter = {"Passed":0, "Failed":0}; 56 | for(var host in hosts_info){ 57 | var host_info = hosts_info[host]; 58 | for(var task in host_info){ 59 | taskstate_counter = updateStateCounter(taskstate_counter, host_info[task]["state"]); 60 | } 61 | } 62 | return taskstate_counter; 63 | } 64 | 65 | /* calculate detailed logs */ 66 | function calculateDetailedTaskStats(hosts_info){ 67 | var run_consists_of = {"playbooks":[], "roles":[], "tasks":[], "hosts":[]} 68 | for(var host in hosts_info){ 69 | run_consists_of["hosts"].push(host) 70 | var host_info = hosts_info[host]; 71 | for(var task in host_info){ 72 | var name = task.split(":") 73 | if(name.length !=3){ 74 | console.log(task + " task doesn't suit Playbook:Role:Task sturct"); 75 | continue; 76 | } 77 | if (run_consists_of["playbooks"].indexOf(name[0]) < 0) { 78 | run_consists_of["playbooks"].push(name[0]) 79 | } 80 | if (run_consists_of["roles"].indexOf(name[1]) < 0 && name[1] != "") { 81 | run_consists_of["roles"].push(name[1]) 82 | } 83 | if (run_consists_of["tasks"].indexOf(name[2]) < 0) { 84 | run_consists_of["tasks"].push(name[2]) 85 | } 86 | } 87 | } 88 | 89 | return run_consists_of; 90 | } 91 | -------------------------------------------------------------------------------- /www-data/js/main.playbook.parser.js: -------------------------------------------------------------------------------- 1 | /* 2 | * javascript library capable of parsing Ansible Playbooks to a desired dictionary 3 | */ 4 | 5 | /* file ext */ 6 | var FileExtRegex = { 7 | none: /[^\.]/, 8 | yaml: /\.ya?ml$/ 9 | } 10 | 11 | function playbookPath(playbook_name){ 12 | return playbooks_www_path + "/" + playbook_name; 13 | } 14 | 15 | /* html-ize role like dict details for playbook */ 16 | function DictToHTML(tasks){ 17 | var innerHTML = ""; 18 | for(var task_idx in tasks){ 19 | innerHTML += GeneralStepToHTML(task_idx, tasks[task_idx]); 20 | } 21 | return innerHTML; 22 | } 23 | 24 | /* html-ize role like list details for playbook */ 25 | function ListToHTML(task_type, tasks){ 26 | if(task_type == "roles"){ 27 | task_type = "role"; 28 | } 29 | var innerHTML = ""; 30 | for(var task_idx in tasks){ 31 | innerHTML += "
      " + GeneralStepToHTML(task_type, tasks[task_idx]) + "
      "; 32 | } 33 | return innerHTML; 34 | } 35 | 36 | /* html-ize value to steps */ 37 | function GeneralStepToHTML(step_key, step){ 38 | var stepHTML = ""; 39 | if(step_key != undefined){ 40 | stepHTML += "
      " + step_key + ":"; 41 | } 42 | if(typeof(step) == "object"){ 43 | stepHTML += "
      "; 44 | if (step.length == undefined){ //dictionary 45 | stepHTML += DictToHTML(step) 46 | } else { //list 47 | stepHTML += ListToHTML(step_key, step) 48 | } 49 | stepHTML += "
      " 50 | } else { 51 | stepHTML += "" + MarkStepByType(step_key, step) + ""; 52 | } 53 | return stepHTML; 54 | } 55 | 56 | /* mark Step if role */ 57 | function MarkStepByType(step_key, step){ 58 | var innerHTML = ""; 59 | if(step_key == "role"){ 60 | innerHTML += "" + step + ""; 61 | } else { 62 | innerHTML = step; 63 | } 64 | return innerHTML; 65 | } 66 | 67 | /* update include for playbook dictionary and mark its html */ 68 | function IncludeToHTML(include_value){ 69 | var innerHTML = ""; 70 | if(typeof(include_value) == "string"){ 71 | include_value = [include_value]; 72 | } 73 | for(var playbook_idx in include_value){ 74 | if(! playbooksInfo.hasOwnProperty(include_value[playbook_idx])){ 75 | playbooksInfo[include_value[playbook_idx]] = YAMLURI2JSON(playbookPath(include_value[playbook_idx])); 76 | } 77 | innerHTML += ""; 78 | } 79 | return innerHTML; 80 | } 81 | 82 | /* convert playbook step to html-ize */ 83 | function PlaybookStepToHTML(playbook_step){ 84 | var stepHTML = ""; 85 | var count = 0; 86 | for(var key in playbook_step){ 87 | if(key == "include"){ 88 | stepHTML += IncludeToHTML(playbook_step[key]) 89 | } else { 90 | stepHTML += GeneralStepToHTML(key, playbook_step[key]) 91 | } 92 | count += 1; 93 | } 94 | return stepHTML; 95 | } 96 | 97 | /* parse all playbooks from a list at given path */ 98 | function parsePlaybooks(playbooks){ 99 | var playbooksInfo = {}; 100 | for(var playbook_idx in playbooks){ 101 | var playbook = playbooks[playbook_idx]; 102 | var playbook_name = playbook; 103 | if(!FileExtRegex.yaml.test(playbook)){ 104 | playbook_name = playbook + ".yml"; 105 | } 106 | 107 | playbooksInfo[playbook] = YAMLURI2JSON(playbookPath(playbook_name)); 108 | } 109 | return playbooksInfo; 110 | } 111 | 112 | /* publishes Playbooks Details to a given div */ 113 | function publishPlaybookDetails(playbook_name, div_id){ 114 | $DOM("#playbookName").innerHTML = playbook_name; 115 | var playbook_steps = playbooksInfo[playbook_name]; 116 | var innerHTML = ""; 117 | for( var step_idx in playbook_steps){ 118 | var step_idx_human = parseInt(step_idx) + 1; 119 | innerHTML += "#" + step_idx_human + " " + PlaybookStepToHTML(playbook_steps[step_idx]) + ""; 120 | } 121 | 122 | $DOM(div_id).innerHTML = innerHTML; 123 | } 124 | 125 | 126 | /*********************** main() ******************* 127 | require following variable pre-defined via dashr-created config/js/main-data.js: 128 | * playbooks : list of all playbook names to be displayed {names should be with file extension unless it's just 'yml'} 129 | * playbooks_www_path : relative path for Playbook files 130 | **************************************************/ 131 | 132 | /* update playbooks sidebar */ 133 | $(function() { 134 | var innerHTML = ""; 135 | for(var playbook_idx in playbooks){ 136 | innerHTML += "
    • " + playbooks[playbook_idx] + "
    • " 137 | } 138 | $DOM("#playbookList").innerHTML = innerHTML; 139 | }); 140 | 141 | /* parse and update playbook */ 142 | var playbooksInfo = parsePlaybooks(playbooks); 143 | 144 | var get_vars = getUrlVars() 145 | if (get_vars.hasOwnProperty("playbook")) { 146 | var q_playbook = decodeURIComponent(get_vars["playbook"]); 147 | if(! playbooksInfo.hasOwnProperty(q_playbook)){ 148 | playbooksInfo[q_playbook] = YAMLURI2JSON([q_playbook]); 149 | } 150 | publishPlaybookDetails(q_playbook, '#playbookDetails') 151 | } else { 152 | publishPlaybookDetails(playbooks[0], "#playbookDetails"); 153 | } 154 | -------------------------------------------------------------------------------- /www-data/js/main.roles.parser.js: -------------------------------------------------------------------------------- 1 | /* 2 | * javascript library capable of parsing Ansible Roles to a desired dictionary 3 | */ 4 | 5 | /* toggle Task Details */ 6 | function toggleTaskDetail(self){ 7 | var task_detail_node = self.parentNode; 8 | var task_details = task_detail_node.querySelectorAll(".task-detail"); 9 | var icon = task_detail_node.querySelector(".toggle-icon"); 10 | var display_mode; 11 | if(icon.classList.contains("icon-plus-sign")){ 12 | icon.classList.remove('icon-plus-sign'); 13 | icon.classList.add('icon-minus-sign'); 14 | display_mode = "block"; 15 | } else { 16 | icon.classList.remove('icon-minus-sign'); 17 | icon.classList.add('icon-plus-sign'); 18 | display_mode = "none"; 19 | } 20 | 21 | for(var task_detail_idx=0; task_detail_idx < task_details.length; task_detail_idx++){ 22 | var task = task_details[task_detail_idx]; 23 | task.style.display = display_mode; 24 | } 25 | } 26 | 27 | /* create a Role Path */ 28 | function rolePath(role_name){ 29 | return roles_www_path + "/" + role_name + "/tasks/main.yml"; 30 | } 31 | 32 | /* parse all roles from a list at given path */ 33 | function parseRoles(roles){ 34 | var rolesInfo = {}; 35 | for(var role_idx in roles){ 36 | var role_name = roles[role_idx]; 37 | var role_uri = rolePath(role_name); 38 | rolesInfo[role_name] = YAMLURI2JSON(role_uri); 39 | } 40 | return rolesInfo; 41 | } 42 | 43 | /* publishes Roles Details to a given div */ 44 | function publishRoleDetails(rolename, div_id){ 45 | $DOM("#roleName").innerHTML = rolename; 46 | var tasks = rolesInfo[rolename]; 47 | var innerHTML = ""; 48 | for(var task_idx in tasks){ 49 | innerHTML += ""; 50 | var task = tasks[task_idx]; 51 | var task_idx_human = parseInt(task_idx) + 1; 52 | var count = 0; 53 | for(var inner_task_key in task){ 54 | if(count == 0){ 55 | innerHTML += "#" + task_idx_human + " " + inner_task_key + ": " + task[inner_task_key] + "
      "; 56 | } else { 57 | innerHTML += "
      " + inner_task_key + ": " + task[inner_task_key] + "
      "; 58 | } 59 | count += 1; 60 | } 61 | innerHTML += "
      "; 62 | } 63 | $DOM(div_id).innerHTML = innerHTML; 64 | } 65 | 66 | 67 | /*********************** main() *******************/ 68 | 69 | /* update roles sidebar */ 70 | $(function() { 71 | var innerHTML = ""; 72 | for(var role_idx in roles){ 73 | innerHTML += "
    • " + roles[role_idx] + "
    • " 74 | } 75 | $DOM("#roleList").innerHTML = innerHTML; 76 | }); 77 | 78 | 79 | /* parse and update roles */ 80 | var rolesInfo = parseRoles(roles); 81 | 82 | var get_vars = getUrlVars() 83 | if (get_vars.hasOwnProperty("role")) { 84 | var q_role = decodeURIComponent(get_vars["role"]); 85 | if(! rolesInfo.hasOwnProperty(q_role)){ 86 | rolesInfo[q_role] = YAMLURI2JSON([q_role]); 87 | } 88 | publishRoleDetails(q_role, '#roleDetails') 89 | } else { 90 | publishRoleDetails(roles[0], '#roleDetails') 91 | } 92 | -------------------------------------------------------------------------------- /www-data/js/plugins.js: -------------------------------------------------------------------------------- 1 | // Avoid `console` errors in browsers that lack a console. 2 | if (!(window.console && console.log)) { 3 | (function() { 4 | var noop = function() {}; 5 | var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn']; 6 | var length = methods.length; 7 | var console = window.console = {}; 8 | while (length--) { 9 | console[methods[length]] = noop; 10 | } 11 | }()); 12 | } 13 | 14 | // Place any jQuery/helper plugins in here. 15 | -------------------------------------------------------------------------------- /www-data/js/vendor/highcharts.exporting.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v4.0.4 (2014-09-02) 3 | Exporting module 4 | 5 | (c) 2010-2014 Torstein Honsi 6 | 7 | License: www.highcharts.com/license 8 | */ 9 | (function(f){var A=f.Chart,t=f.addEvent,B=f.removeEvent,l=f.createElement,o=f.discardElement,v=f.css,k=f.merge,r=f.each,p=f.extend,D=Math.max,j=document,C=window,E=f.isTouchDevice,F=f.Renderer.prototype.symbols,s=f.getOptions(),y;p(s.lang,{printChart:"Print chart",downloadPNG:"Download PNG image",downloadJPEG:"Download JPEG image",downloadPDF:"Download PDF document",downloadSVG:"Download SVG vector image",contextButtonTitle:"Chart context menu"});s.navigation={menuStyle:{border:"1px solid #A0A0A0", 10 | background:"#FFFFFF",padding:"5px 0"},menuItemStyle:{padding:"0 10px",background:"none",color:"#303030",fontSize:E?"14px":"11px"},menuItemHoverStyle:{background:"#4572A5",color:"#FFFFFF"},buttonOptions:{symbolFill:"#E0E0E0",symbolSize:14,symbolStroke:"#666",symbolStrokeWidth:3,symbolX:12.5,symbolY:10.5,align:"right",buttonSpacing:3,height:22,theme:{fill:"white",stroke:"none"},verticalAlign:"top",width:24}};s.exporting={type:"image/png",url:"http://export.highcharts.com/",buttons:{contextButton:{menuClassName:"highcharts-contextmenu", 11 | symbol:"menu",_titleKey:"contextButtonTitle",menuItems:[{textKey:"printChart",onclick:function(){this.print()}},{separator:!0},{textKey:"downloadPNG",onclick:function(){this.exportChart()}},{textKey:"downloadJPEG",onclick:function(){this.exportChart({type:"image/jpeg"})}},{textKey:"downloadPDF",onclick:function(){this.exportChart({type:"application/pdf"})}},{textKey:"downloadSVG",onclick:function(){this.exportChart({type:"image/svg+xml"})}}]}}};f.post=function(b,a,d){var c,b=l("form",k({method:"post", 12 | action:b,enctype:"multipart/form-data"},d),{display:"none"},j.body);for(c in a)l("input",{type:"hidden",name:c,value:a[c]},null,b);b.submit();o(b)};p(A.prototype,{getSVG:function(b){var a=this,d,c,z,h,g=k(a.options,b);if(!j.createElementNS)j.createElementNS=function(a,b){return j.createElement(b)};b=l("div",null,{position:"absolute",top:"-9999em",width:a.chartWidth+"px",height:a.chartHeight+"px"},j.body);c=a.renderTo.style.width;h=a.renderTo.style.height;c=g.exporting.sourceWidth||g.chart.width|| 13 | /px$/.test(c)&&parseInt(c,10)||600;h=g.exporting.sourceHeight||g.chart.height||/px$/.test(h)&&parseInt(h,10)||400;p(g.chart,{animation:!1,renderTo:b,forExport:!0,width:c,height:h});g.exporting.enabled=!1;g.series=[];r(a.series,function(a){z=k(a.options,{animation:!1,enableMouseTracking:!1,showCheckbox:!1,visible:a.visible});z.isInternal||g.series.push(z)});d=new f.Chart(g,a.callback);r(["xAxis","yAxis"],function(b){r(a[b],function(a,c){var g=d[b][c],f=a.getExtremes(),h=f.userMin,f=f.userMax;g&&(h!== 14 | void 0||f!==void 0)&&g.setExtremes(h,f,!0,!1)})});c=d.container.innerHTML;g=null;d.destroy();o(b);c=c.replace(/zIndex="[^"]+"/g,"").replace(/isShadow="[^"]+"/g,"").replace(/symbolName="[^"]+"/g,"").replace(/jQuery[0-9]+="[^"]+"/g,"").replace(/url\([^#]+#/g,"url(#").replace(/.*?$/,"").replace(/(fill|stroke)="rgba\(([ 0-9]+,[ 0-9]+,[ 0-9]+),([ 0-9\.]+)\)"/g,'$1="rgb($2)" $1-opacity="$3"').replace(/ /g, 15 | " ").replace(/­/g,"­").replace(//g,'xlink:href="$1"/>').replace(/id=([^" >]+)/g,'id="$1"').replace(/class=([^" >]+)/g,'class="$1"').replace(/ transform /g," ").replace(/:(path|rect)/g,"$1").replace(/style="([^"]+)"/g,function(a){return a.toLowerCase()});return c=c.replace(/(url\(#highcharts-[0-9]+)"/g,"$1").replace(/"/g,"'")},exportChart:function(b,a){var b= 16 | b||{},d=this.options.exporting,d=this.getSVG(k({chart:{borderRadius:0}},d.chartOptions,a,{exporting:{sourceWidth:b.sourceWidth||d.sourceWidth,sourceHeight:b.sourceHeight||d.sourceHeight}})),b=k(this.options.exporting,b);f.post(b.url,{filename:b.filename||"chart",type:b.type,width:b.width||0,scale:b.scale||2,svg:d},b.formAttributes)},print:function(){var b=this,a=b.container,d=[],c=a.parentNode,f=j.body,h=f.childNodes;if(!b.isPrinting)b.isPrinting=!0,r(h,function(a,b){if(a.nodeType===1)d[b]=a.style.display, 17 | a.style.display="none"}),f.appendChild(a),C.focus(),C.print(),setTimeout(function(){c.appendChild(a);r(h,function(a,b){if(a.nodeType===1)a.style.display=d[b]});b.isPrinting=!1},1E3)},contextMenu:function(b,a,d,c,f,h,g){var e=this,k=e.options.navigation,q=k.menuItemStyle,m=e.chartWidth,n=e.chartHeight,j="cache-"+b,i=e[j],u=D(f,h),w,x,o,s=function(a){e.pointer.inClass(a.target,b)||x()};if(!i)e[j]=i=l("div",{className:b},{position:"absolute",zIndex:1E3,padding:u+"px"},e.container),w=l("div",null,p({MozBoxShadow:"3px 3px 10px #888", 18 | WebkitBoxShadow:"3px 3px 10px #888",boxShadow:"3px 3px 10px #888"},k.menuStyle),i),x=function(){v(i,{display:"none"});g&&g.setState(0);e.openMenu=!1},t(i,"mouseleave",function(){o=setTimeout(x,500)}),t(i,"mouseenter",function(){clearTimeout(o)}),t(document,"mouseup",s),t(e,"destroy",function(){B(document,"mouseup",s)}),r(a,function(a){if(a){var b=a.separator?l("hr",null,null,w):l("div",{onmouseover:function(){v(this,k.menuItemHoverStyle)},onmouseout:function(){v(this,q)},onclick:function(){x();a.onclick.apply(e, 19 | arguments)},innerHTML:a.text||e.options.lang[a.textKey]},p({cursor:"pointer"},q),w);e.exportDivElements.push(b)}}),e.exportDivElements.push(w,i),e.exportMenuWidth=i.offsetWidth,e.exportMenuHeight=i.offsetHeight;a={display:"block"};d+e.exportMenuWidth>m?a.right=m-d-f-u+"px":a.left=d-u+"px";c+h+e.exportMenuHeight>n&&g.alignOptions.verticalAlign!=="top"?a.bottom=n-c-u+"px":a.top=c+h-u+"px";v(i,a);e.openMenu=!0},addButton:function(b){var a=this,d=a.renderer,c=k(a.options.navigation.buttonOptions,b),j= 20 | c.onclick,h=c.menuItems,g,e,l={stroke:c.symbolStroke,fill:c.symbolFill},q=c.symbolSize||12;if(!a.btnCount)a.btnCount=0;if(!a.exportDivElements)a.exportDivElements=[],a.exportSVGElements=[];if(c.enabled!==!1){var m=c.theme,n=m.states,o=n&&n.hover,n=n&&n.select,i;delete m.states;j?i=function(){j.apply(a,arguments)}:h&&(i=function(){a.contextMenu(e.menuClassName,h,e.translateX,e.translateY,e.width,e.height,e);e.setState(2)});c.text&&c.symbol?m.paddingLeft=f.pick(m.paddingLeft,25):c.text||p(m,{width:c.width, 21 | height:c.height,padding:0});e=d.button(c.text,0,0,i,m,o,n).attr({title:a.options.lang[c._titleKey],"stroke-linecap":"round"});e.menuClassName=b.menuClassName||"highcharts-menu-"+a.btnCount++;c.symbol&&(g=d.symbol(c.symbol,c.symbolX-q/2,c.symbolY-q/2,q,q).attr(p(l,{"stroke-width":c.symbolStrokeWidth||1,zIndex:1})).add(e));e.add().align(p(c,{width:e.width,x:f.pick(c.x,y)}),!0,"spacingBox");y+=(e.width+c.buttonSpacing)*(c.align==="right"?-1:1);a.exportSVGElements.push(e,g)}},destroyExport:function(b){var b= 22 | b.target,a,d;for(a=0;ai;i++)if(h.test(f[i].className)){if(c)return f[i];d[j]=f[i],j++}return d}}()}),a.register("javve-get-attribute/index.js",function(a,b,c){c.exports=function(a,b){var c=a.getAttribute&&a.getAttribute(b)||null;if(!c)for(var d=a.attributes,e=d.length,f=0;e>f;f++)void 0!==b[f]&&b[f].nodeName===b&&(c=b[f].nodeValue);return c}}),a.register("javve-natural-sort/index.js",function(a,b,c){c.exports=function(a,b,c){var d,e,f=/(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,g=/(^[ ]*|[ ]*$)/g,h=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,i=/^0x[0-9a-f]+$/i,j=/^0/,c=c||{},k=function(a){return c.insensitive&&(""+a).toLowerCase()||""+a},l=k(a).replace(g,"")||"",m=k(b).replace(g,"")||"",n=l.replace(f,"\x00$1\x00").replace(/\0$/,"").replace(/^\0/,"").split("\x00"),o=m.replace(f,"\x00$1\x00").replace(/\0$/,"").replace(/^\0/,"").split("\x00"),p=parseInt(l.match(i))||1!=n.length&&l.match(h)&&Date.parse(l),q=parseInt(m.match(i))||p&&m.match(h)&&Date.parse(m)||null,r=c.desc?-1:1;if(q){if(q>p)return-1*r;if(p>q)return 1*r}for(var s=0,t=Math.max(n.length,o.length);t>s;s++){if(d=!(n[s]||"").match(j)&&parseFloat(n[s])||n[s]||0,e=!(o[s]||"").match(j)&&parseFloat(o[s])||o[s]||0,isNaN(d)!==isNaN(e))return isNaN(d)?1:-1;if(typeof d!=typeof e&&(d+="",e+=""),e>d)return-1*r;if(d>e)return 1*r}return 0}}),a.register("javve-to-string/index.js",function(a,b,c){c.exports=function(a){return a=void 0===a?"":a,a=null===a?"":a,a=a.toString()}}),a.register("component-type/index.js",function(a,b,c){var d=Object.prototype.toString;c.exports=function(a){switch(d.call(a)){case"[object Date]":return"date";case"[object RegExp]":return"regexp";case"[object Arguments]":return"arguments";case"[object Array]":return"array";case"[object Error]":return"error"}return null===a?"null":void 0===a?"undefined":a!==a?"nan":a&&1===a.nodeType?"element":typeof a.valueOf()}}),a.register("list.js/index.js",function(a,b,c){!function(a,d){"use strict";var e=a.document,f=b("get-by-class"),g=b("extend"),h=b("indexof"),i=function(a,c,i){var j,k=this,l=b("./src/item")(k),m=b("./src/add-async")(k),n=b("./src/parse")(k);j={start:function(){k.listClass="list",k.searchClass="search",k.sortClass="sort",k.page=200,k.i=1,k.items=[],k.visibleItems=[],k.matchingItems=[],k.searched=!1,k.filtered=!1,k.handlers={updated:[]},k.plugins={},k.helpers={getByClass:f,extend:g,indexOf:h},g(k,c),k.listContainer="string"==typeof a?e.getElementById(a):a,k.listContainer&&(k.list=f(k.listContainer,k.listClass,!0),k.templater=b("./src/templater")(k),k.search=b("./src/search")(k),k.filter=b("./src/filter")(k),k.sort=b("./src/sort")(k),this.items(),k.update(),this.plugins())},items:function(){n(k.list),i!==d&&k.add(i)},plugins:function(){for(var a=0;af;f++){var h=null;a[f]instanceof l?(h=a[f],h.reload()):(e=k.items.length>k.page?!0:!1,h=new l(a[f],d,e)),k.items.push(h),c.push(h)}return k.update(),c},this.show=function(a,b){return this.i=a,this.page=b,k.update(),k},this.remove=function(a,b,c){for(var d=0,e=0,f=k.items.length;f>e;e++)k.items[e].values()[a]==b&&(k.templater.remove(k.items[e],c),k.items.splice(e,1),f--,e--,d++);return k.update(),d},this.get=function(a,b){for(var c=[],d=0,e=k.items.length;e>d;d++){var f=k.items[d];f.values()[a]==b&&c.push(f)}return c},this.size=function(){return k.items.length},this.clear=function(){return k.templater.clear(),k.items=[],k},this.on=function(a,b){return k.handlers[a].push(b),k},this.off=function(a,b){var c=k.handlers[a],d=h(c,b);return d>-1&&c.splice(d,1),k},this.trigger=function(a){for(var b=k.handlers[a].length;b--;)k.handlers[a][b](k);return k},this.reset={filter:function(){for(var a=k.items,b=a.length;b--;)a[b].filtered=!1;return k},search:function(){for(var a=k.items,b=a.length;b--;)a[b].found=!1;return k}},this.update=function(){var a=k.items,b=a.length;k.visibleItems=[],k.matchingItems=[],k.templater.clear();for(var c=0;b>c;c++)a[c].matching()&&k.matchingItems.length+1>=k.i&&k.visibleItems.lengthb;b++)j.item(a.items[b])},item:function(a){a.found=!1;for(var b=0,d=c.length;d>b;b++)if(j.values(a.values(),c[b]))return a.found=!0,void 0},values:function(a,c){return a.hasOwnProperty(c)&&(b=f(a[c]).toLowerCase(),""!==g&&b.search(g)>-1)?!0:!1},reset:function(){a.reset.search(),a.searched=!1}},k=function(b){return a.trigger("searchStart"),i.resetList(),i.setSearchString(b),i.setOptions(arguments),i.setColumns(),""===g?j.reset():(a.searched=!0,h?h(g,c):j.list()),a.update(),a.trigger("searchComplete"),a.visibleItems};return a.handlers.searchStart=a.handlers.searchStart||[],a.handlers.searchComplete=a.handlers.searchComplete||[],d.bind(e(a.listContainer,a.searchClass),"keyup",function(b){var c=b.target||b.srcElement,d=""===c.value&&!a.searched;d||k(c.value)}),d.bind(e(a.listContainer,a.searchClass),"input",function(a){var b=a.target||a.srcElement;""===b.value&&k("")}),a.helpers.toString=f,k}}),a.register("list.js/src/sort.js",function(a,b,c){var d=b("natural-sort"),e=b("classes"),f=b("events"),g=b("get-by-class"),h=b("get-attribute");c.exports=function(a){a.sortFunction=a.sortFunction||function(a,b,c){return c.desc="desc"==c.order?!0:!1,d(a.values()[c.valueName],b.values()[c.valueName],c)};var b={els:void 0,clear:function(){for(var a=0,c=b.els.length;c>a;a++)e(b.els[a]).remove("asc"),e(b.els[a]).remove("desc")},getOrder:function(a){var b=h(a,"data-order");return"asc"==b||"desc"==b?b:e(a).has("desc")?"asc":e(a).has("asc")?"desc":"asc"},getInSensitive:function(a,b){var c=h(a,"data-insensitive");b.insensitive="true"===c?!0:!1},setOrder:function(a){for(var c=0,d=b.els.length;d>c;c++){var f=b.els[c];if(h(f,"data-sort")===a.valueName){var g=h(f,"data-order");"asc"==g||"desc"==g?g==a.order&&e(f).add(a.order):e(f).add(a.order)}}}},c=function(){a.trigger("sortStart"),options={};var c=arguments[0].currentTarget||arguments[0].srcElement||void 0;c?(options.valueName=h(c,"data-sort"),b.getInSensitive(c,options),options.order=b.getOrder(c)):(options=arguments[1]||options,options.valueName=arguments[0],options.order=options.order||"asc",options.insensitive="undefined"==typeof options.insensitive?!0:options.insensitive),b.clear(),b.setOrder(options),options.sortFunction=options.sortFunction||a.sortFunction,a.items.sort(function(a,b){return options.sortFunction(a,b,options)}),a.update(),a.trigger("sortComplete")};return a.handlers.sortStart=a.handlers.sortStart||[],a.handlers.sortComplete=a.handlers.sortComplete||[],b.els=g(a.listContainer,a.sortClass),f.bind(b.els,"click",c),a.on("searchStart",b.clear),a.on("filterStart",b.clear),a.helpers.classes=e,a.helpers.naturalSort=d,a.helpers.events=f,a.helpers.getAttribute=h,c}}),a.register("list.js/src/item.js",function(a,b,c){c.exports=function(a){return function(b,c,d){var e=this;this._values={},this.found=!1,this.filtered=!1;var f=function(b,c,d){if(void 0===c)d?e.values(b,d):e.values(b);else{e.elm=c;var f=a.templater.get(e,b);e.values(f)}};this.values=function(b,c){if(void 0===b)return e._values;for(var d in b)e._values[d]=b[d];c!==!0&&a.templater.set(e,e.values())},this.show=function(){a.templater.show(e)},this.hide=function(){a.templater.hide(e)},this.matching=function(){return a.filtered&&a.searched&&e.found&&e.filtered||a.filtered&&!a.searched&&e.filtered||!a.filtered&&a.searched&&e.found||!a.filtered&&!a.searched},this.visible=function(){return e.elm.parentNode==a.list?!0:!1},f(b,c,d)}}}),a.register("list.js/src/templater.js",function(a,b,c){var d=b("get-by-class"),e=function(a){function b(b){if(void 0===b){for(var c=a.list.childNodes,d=0,e=c.length;e>d;d++)if(void 0===c[d].data)return c[d];return null}if(-1!==b.indexOf("<")){var f=document.createElement("div");return f.innerHTML=b,f.firstChild}return document.getElementById(a.item)}var c=b(a.item),e=this;this.get=function(a,b){e.create(a);for(var c={},f=0,g=b.length;g>f;f++){var h=d(a.elm,b[f],!0);c[b[f]]=h?h.innerHTML:""}return c},this.set=function(a,b){if(!e.create(a))for(var c in b)if(b.hasOwnProperty(c)){var f=d(a.elm,c,!0);f&&("IMG"===f.tagName&&""!==b[c]?f.src=b[c]:f.innerHTML=b[c])}},this.create=function(a){if(void 0!==a.elm)return!1;var b=c.cloneNode(!0);return b.removeAttribute("id"),a.elm=b,e.set(a,a.values()),!0},this.remove=function(b){a.list.removeChild(b.elm)},this.show=function(b){e.create(b),a.list.appendChild(b.elm)},this.hide=function(b){void 0!==b.elm&&b.elm.parentNode===a.list&&a.list.removeChild(b.elm)},this.clear=function(){if(a.list.hasChildNodes())for(;a.list.childNodes.length>=1;)a.list.removeChild(a.list.firstChild)}};c.exports=function(a){return new e(a)}}),a.register("list.js/src/filter.js",function(a,b,c){c.exports=function(a){return a.handlers.filterStart=a.handlers.filterStart||[],a.handlers.filterComplete=a.handlers.filterComplete||[],function(b){if(a.trigger("filterStart"),a.i=1,a.reset.filter(),void 0===b)a.filtered=!1;else{a.filtered=!0;for(var c=a.items,d=0,e=c.length;e>d;d++){var f=c[d];f.filtered=b(f)?!0:!1}}return a.update(),a.trigger("filterComplete"),a.visibleItems}}}),a.register("list.js/src/add-async.js",function(a,b,c){c.exports=function(a){return function(b,c,d){var e=b.splice(0,100);d=d||[],d=d.concat(a.add(e)),b.length>0?setTimeout(function(){addAsync(b,c,d)},10):(a.update(),c(d))}}}),a.register("list.js/src/parse.js",function(a,b,c){c.exports=function(a){var c=b("./item")(a),d=function(a){for(var b=a.childNodes,c=[],d=0,e=b.length;e>d;d++)void 0===b[d].data&&c.push(b[d]);return c},e=function(b,d){for(var e=0,f=b.length;f>e;e++)a.items.push(new c(d,b[e]))},f=function(b,c){var d=b.splice(0,100);e(d,c),b.length>0?setTimeout(function(){init.items.indexAsync(b,c)},10):a.update()};return function(){var b=d(a.list),c=a.valueNames;a.indexAsync?f(b,c):e(b,c)}}}),a.alias("component-classes/index.js","list.js/deps/classes/index.js"),a.alias("component-classes/index.js","classes/index.js"),a.alias("component-indexof/index.js","component-classes/deps/indexof/index.js"),a.alias("segmentio-extend/index.js","list.js/deps/extend/index.js"),a.alias("segmentio-extend/index.js","extend/index.js"),a.alias("component-indexof/index.js","list.js/deps/indexof/index.js"),a.alias("component-indexof/index.js","indexof/index.js"),a.alias("javve-events/index.js","list.js/deps/events/index.js"),a.alias("javve-events/index.js","events/index.js"),a.alias("component-event/index.js","javve-events/deps/event/index.js"),a.alias("timoxley-to-array/index.js","javve-events/deps/to-array/index.js"),a.alias("javve-get-by-class/index.js","list.js/deps/get-by-class/index.js"),a.alias("javve-get-by-class/index.js","get-by-class/index.js"),a.alias("javve-get-attribute/index.js","list.js/deps/get-attribute/index.js"),a.alias("javve-get-attribute/index.js","get-attribute/index.js"),a.alias("javve-natural-sort/index.js","list.js/deps/natural-sort/index.js"),a.alias("javve-natural-sort/index.js","natural-sort/index.js"),a.alias("javve-to-string/index.js","list.js/deps/to-string/index.js"),a.alias("javve-to-string/index.js","list.js/deps/to-string/index.js"),a.alias("javve-to-string/index.js","to-string/index.js"),a.alias("javve-to-string/index.js","javve-to-string/index.js"),a.alias("component-type/index.js","list.js/deps/type/index.js"),a.alias("component-type/index.js","type/index.js"),"object"==typeof exports?module.exports=a("list.js"):"function"==typeof define&&define.amd?define(function(){return a("list.js")}):this.List=a("list.js")}(); -------------------------------------------------------------------------------- /www-data/js/vendor/list.pagination.js: -------------------------------------------------------------------------------- 1 | ;(function(){ 2 | 3 | /** 4 | * Require the given path. 5 | * 6 | * @param {String} path 7 | * @return {Object} exports 8 | * @api public 9 | */ 10 | 11 | function require(path, parent, orig) { 12 | var resolved = require.resolve(path); 13 | 14 | // lookup failed 15 | if (null == resolved) { 16 | orig = orig || path; 17 | parent = parent || 'root'; 18 | var err = new Error('Failed to require "' + orig + '" from "' + parent + '"'); 19 | err.path = orig; 20 | err.parent = parent; 21 | err.require = true; 22 | throw err; 23 | } 24 | 25 | var module = require.modules[resolved]; 26 | 27 | // perform real require() 28 | // by invoking the module's 29 | // registered function 30 | if (!module._resolving && !module.exports) { 31 | var mod = {}; 32 | mod.exports = {}; 33 | mod.client = mod.component = true; 34 | module._resolving = true; 35 | module.call(this, mod.exports, require.relative(resolved), mod); 36 | delete module._resolving; 37 | module.exports = mod.exports; 38 | } 39 | 40 | return module.exports; 41 | } 42 | 43 | /** 44 | * Registered modules. 45 | */ 46 | 47 | require.modules = {}; 48 | 49 | /** 50 | * Registered aliases. 51 | */ 52 | 53 | require.aliases = {}; 54 | 55 | /** 56 | * Resolve `path`. 57 | * 58 | * Lookup: 59 | * 60 | * - PATH/index.js 61 | * - PATH.js 62 | * - PATH 63 | * 64 | * @param {String} path 65 | * @return {String} path or null 66 | * @api private 67 | */ 68 | 69 | require.resolve = function(path) { 70 | if (path.charAt(0) === '/') path = path.slice(1); 71 | 72 | var paths = [ 73 | path, 74 | path + '.js', 75 | path + '.json', 76 | path + '/index.js', 77 | path + '/index.json' 78 | ]; 79 | 80 | for (var i = 0; i < paths.length; i++) { 81 | var path = paths[i]; 82 | if (require.modules.hasOwnProperty(path)) return path; 83 | if (require.aliases.hasOwnProperty(path)) return require.aliases[path]; 84 | } 85 | }; 86 | 87 | /** 88 | * Normalize `path` relative to the current path. 89 | * 90 | * @param {String} curr 91 | * @param {String} path 92 | * @return {String} 93 | * @api private 94 | */ 95 | 96 | require.normalize = function(curr, path) { 97 | var segs = []; 98 | 99 | if ('.' != path.charAt(0)) return path; 100 | 101 | curr = curr.split('/'); 102 | path = path.split('/'); 103 | 104 | for (var i = 0; i < path.length; ++i) { 105 | if ('..' == path[i]) { 106 | curr.pop(); 107 | } else if ('.' != path[i] && '' != path[i]) { 108 | segs.push(path[i]); 109 | } 110 | } 111 | 112 | return curr.concat(segs).join('/'); 113 | }; 114 | 115 | /** 116 | * Register module at `path` with callback `definition`. 117 | * 118 | * @param {String} path 119 | * @param {Function} definition 120 | * @api private 121 | */ 122 | 123 | require.register = function(path, definition) { 124 | require.modules[path] = definition; 125 | }; 126 | 127 | /** 128 | * Alias a module definition. 129 | * 130 | * @param {String} from 131 | * @param {String} to 132 | * @api private 133 | */ 134 | 135 | require.alias = function(from, to) { 136 | if (!require.modules.hasOwnProperty(from)) { 137 | throw new Error('Failed to alias "' + from + '", it does not exist'); 138 | } 139 | require.aliases[to] = from; 140 | }; 141 | 142 | /** 143 | * Return a require function relative to the `parent` path. 144 | * 145 | * @param {String} parent 146 | * @return {Function} 147 | * @api private 148 | */ 149 | 150 | require.relative = function(parent) { 151 | var p = require.normalize(parent, '..'); 152 | 153 | /** 154 | * lastIndexOf helper. 155 | */ 156 | 157 | function lastIndexOf(arr, obj) { 158 | var i = arr.length; 159 | while (i--) { 160 | if (arr[i] === obj) return i; 161 | } 162 | return -1; 163 | } 164 | 165 | /** 166 | * The relative require() itself. 167 | */ 168 | 169 | function localRequire(path) { 170 | var resolved = localRequire.resolve(path); 171 | return require(resolved, parent, path); 172 | } 173 | 174 | /** 175 | * Resolve relative to the parent. 176 | */ 177 | 178 | localRequire.resolve = function(path) { 179 | var c = path.charAt(0); 180 | if ('/' == c) return path.slice(1); 181 | if ('.' == c) return require.normalize(p, path); 182 | 183 | // resolve deps by returning 184 | // the dep in the nearest "deps" 185 | // directory 186 | var segs = parent.split('/'); 187 | var i = lastIndexOf(segs, 'deps') + 1; 188 | if (!i) i = 0; 189 | path = segs.slice(0, i + 1).join('/') + '/deps/' + path; 190 | return path; 191 | }; 192 | 193 | /** 194 | * Check if module is defined at `path`. 195 | */ 196 | 197 | localRequire.exists = function(path) { 198 | return require.modules.hasOwnProperty(localRequire.resolve(path)); 199 | }; 200 | 201 | return localRequire; 202 | }; 203 | require.register("component-classes/index.js", function(exports, require, module){ 204 | /** 205 | * Module dependencies. 206 | */ 207 | 208 | var index = require('indexof'); 209 | 210 | /** 211 | * Whitespace regexp. 212 | */ 213 | 214 | var re = /\s+/; 215 | 216 | /** 217 | * toString reference. 218 | */ 219 | 220 | var toString = Object.prototype.toString; 221 | 222 | /** 223 | * Wrap `el` in a `ClassList`. 224 | * 225 | * @param {Element} el 226 | * @return {ClassList} 227 | * @api public 228 | */ 229 | 230 | module.exports = function(el){ 231 | return new ClassList(el); 232 | }; 233 | 234 | /** 235 | * Initialize a new ClassList for `el`. 236 | * 237 | * @param {Element} el 238 | * @api private 239 | */ 240 | 241 | function ClassList(el) { 242 | if (!el) throw new Error('A DOM element reference is required'); 243 | this.el = el; 244 | this.list = el.classList; 245 | } 246 | 247 | /** 248 | * Add class `name` if not already present. 249 | * 250 | * @param {String} name 251 | * @return {ClassList} 252 | * @api public 253 | */ 254 | 255 | ClassList.prototype.add = function(name){ 256 | // classList 257 | if (this.list) { 258 | this.list.add(name); 259 | return this; 260 | } 261 | 262 | // fallback 263 | var arr = this.array(); 264 | var i = index(arr, name); 265 | if (!~i) arr.push(name); 266 | this.el.className = arr.join(' '); 267 | return this; 268 | }; 269 | 270 | /** 271 | * Remove class `name` when present, or 272 | * pass a regular expression to remove 273 | * any which match. 274 | * 275 | * @param {String|RegExp} name 276 | * @return {ClassList} 277 | * @api public 278 | */ 279 | 280 | ClassList.prototype.remove = function(name){ 281 | if ('[object RegExp]' == toString.call(name)) { 282 | return this.removeMatching(name); 283 | } 284 | 285 | // classList 286 | if (this.list) { 287 | this.list.remove(name); 288 | return this; 289 | } 290 | 291 | // fallback 292 | var arr = this.array(); 293 | var i = index(arr, name); 294 | if (~i) arr.splice(i, 1); 295 | this.el.className = arr.join(' '); 296 | return this; 297 | }; 298 | 299 | /** 300 | * Remove all classes matching `re`. 301 | * 302 | * @param {RegExp} re 303 | * @return {ClassList} 304 | * @api private 305 | */ 306 | 307 | ClassList.prototype.removeMatching = function(re){ 308 | var arr = this.array(); 309 | for (var i = 0; i < arr.length; i++) { 310 | if (re.test(arr[i])) { 311 | this.remove(arr[i]); 312 | } 313 | } 314 | return this; 315 | }; 316 | 317 | /** 318 | * Toggle class `name`, can force state via `force`. 319 | * 320 | * For browsers that support classList, but do not support `force` yet, 321 | * the mistake will be detected and corrected. 322 | * 323 | * @param {String} name 324 | * @param {Boolean} force 325 | * @return {ClassList} 326 | * @api public 327 | */ 328 | 329 | ClassList.prototype.toggle = function(name, force){ 330 | // classList 331 | if (this.list) { 332 | if ("undefined" !== typeof force) { 333 | if (force !== this.list.toggle(name, force)) { 334 | this.list.toggle(name); // toggle again to correct 335 | } 336 | } else { 337 | this.list.toggle(name); 338 | } 339 | return this; 340 | } 341 | 342 | // fallback 343 | if ("undefined" !== typeof force) { 344 | if (!force) { 345 | this.remove(name); 346 | } else { 347 | this.add(name); 348 | } 349 | } else { 350 | if (this.has(name)) { 351 | this.remove(name); 352 | } else { 353 | this.add(name); 354 | } 355 | } 356 | 357 | return this; 358 | }; 359 | 360 | /** 361 | * Return an array of classes. 362 | * 363 | * @return {Array} 364 | * @api public 365 | */ 366 | 367 | ClassList.prototype.array = function(){ 368 | var str = this.el.className.replace(/^\s+|\s+$/g, ''); 369 | var arr = str.split(re); 370 | if ('' === arr[0]) arr.shift(); 371 | return arr; 372 | }; 373 | 374 | /** 375 | * Check if class `name` is present. 376 | * 377 | * @param {String} name 378 | * @return {ClassList} 379 | * @api public 380 | */ 381 | 382 | ClassList.prototype.has = 383 | ClassList.prototype.contains = function(name){ 384 | return this.list 385 | ? this.list.contains(name) 386 | : !! ~index(this.array(), name); 387 | }; 388 | 389 | }); 390 | require.register("component-event/index.js", function(exports, require, module){ 391 | var bind = window.addEventListener ? 'addEventListener' : 'attachEvent', 392 | unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent', 393 | prefix = bind !== 'addEventListener' ? 'on' : ''; 394 | 395 | /** 396 | * Bind `el` event `type` to `fn`. 397 | * 398 | * @param {Element} el 399 | * @param {String} type 400 | * @param {Function} fn 401 | * @param {Boolean} capture 402 | * @return {Function} 403 | * @api public 404 | */ 405 | 406 | exports.bind = function(el, type, fn, capture){ 407 | el[bind](prefix + type, fn, capture || false); 408 | return fn; 409 | }; 410 | 411 | /** 412 | * Unbind `el` event `type`'s callback `fn`. 413 | * 414 | * @param {Element} el 415 | * @param {String} type 416 | * @param {Function} fn 417 | * @param {Boolean} capture 418 | * @return {Function} 419 | * @api public 420 | */ 421 | 422 | exports.unbind = function(el, type, fn, capture){ 423 | el[unbind](prefix + type, fn, capture || false); 424 | return fn; 425 | }; 426 | }); 427 | require.register("component-indexof/index.js", function(exports, require, module){ 428 | module.exports = function(arr, obj){ 429 | if (arr.indexOf) return arr.indexOf(obj); 430 | for (var i = 0; i < arr.length; ++i) { 431 | if (arr[i] === obj) return i; 432 | } 433 | return -1; 434 | }; 435 | }); 436 | require.register("list.pagination.js/index.js", function(exports, require, module){ 437 | var classes = require('classes'), 438 | events = require('event'); 439 | 440 | module.exports = function(options) { 441 | options = options || {}; 442 | 443 | var pagingList, 444 | list; 445 | 446 | var refresh = function() { 447 | var item, 448 | l = list.matchingItems.length, 449 | index = list.i, 450 | page = list.page, 451 | pages = Math.ceil(l / page), 452 | currentPage = Math.ceil((index / page)), 453 | innerWindow = options.innerWindow || 2, 454 | left = options.left || options.outerWindow || 0, 455 | right = options.right || options.outerWindow || 0; 456 | 457 | right = pages - right; 458 | 459 | pagingList.clear(); 460 | for (var i = 1; i <= pages; i++) { 461 | var className = (currentPage === i) ? "active" : ""; 462 | 463 | //console.log(i, left, right, currentPage, (currentPage - innerWindow), (currentPage + innerWindow), className); 464 | 465 | if (is.number(i, left, right, currentPage, innerWindow)) { 466 | item = pagingList.add({ 467 | page: i, 468 | dotted: false 469 | })[0]; 470 | if (className) { 471 | classes(item.elm).add(className); 472 | } 473 | addEvent(item.elm, i, page); 474 | } else if (is.dotted(i, left, right, currentPage, innerWindow, pagingList.size())) { 475 | item = pagingList.add({ 476 | page: "...", 477 | dotted: true 478 | })[0]; 479 | classes(item.elm).add("disabled"); 480 | } 481 | } 482 | }; 483 | 484 | var is = { 485 | number: function(i, left, right, currentPage, innerWindow) { 486 | return this.left(i, left) || this.right(i, right) || this.innerWindow(i, currentPage, innerWindow); 487 | }, 488 | left: function(i, left) { 489 | return (i <= left); 490 | }, 491 | right: function(i, right) { 492 | return (i > right); 493 | }, 494 | innerWindow: function(i, currentPage, innerWindow) { 495 | return ( i >= (currentPage - innerWindow) && i <= (currentPage + innerWindow)); 496 | }, 497 | dotted: function(i, left, right, currentPage, innerWindow, currentPageItem) { 498 | return this.dottedLeft(i, left, right, currentPage, innerWindow) || (this.dottedRight(i, left, right, currentPage, innerWindow, currentPageItem)); 499 | }, 500 | dottedLeft: function(i, left, right, currentPage, innerWindow) { 501 | return ((i == (left + 1)) && !this.innerWindow(i, currentPage, innerWindow) && !this.right(i, right)); 502 | }, 503 | dottedRight: function(i, left, right, currentPage, innerWindow, currentPageItem) { 504 | if (pagingList.items[currentPageItem-1].values().dotted) { 505 | return false; 506 | } else { 507 | return ((i == (right)) && !this.innerWindow(i, currentPage, innerWindow) && !this.right(i, right)); 508 | } 509 | } 510 | }; 511 | 512 | var addEvent = function(elm, i, page) { 513 | events.bind(elm, 'click', function() { 514 | list.show((i-1)*page + 1, page); 515 | }); 516 | }; 517 | 518 | return { 519 | init: function(parentList) { 520 | list = parentList; 521 | pagingList = new List(list.listContainer.id, { 522 | listClass: options.paginationClass || 'pagination', 523 | item: "
    • ", 524 | valueNames: ['page', 'dotted'], 525 | searchClass: 'pagination-search-that-is-not-supposed-to-exist', 526 | sortClass: 'pagination-sort-that-is-not-supposed-to-exist' 527 | }); 528 | list.on('updated', refresh); 529 | refresh(); 530 | }, 531 | name: options.name || "pagination" 532 | }; 533 | }; 534 | 535 | }); 536 | 537 | 538 | 539 | 540 | 541 | 542 | require.alias("component-classes/index.js", "list.pagination.js/deps/classes/index.js"); 543 | require.alias("component-classes/index.js", "classes/index.js"); 544 | require.alias("component-indexof/index.js", "component-classes/deps/indexof/index.js"); 545 | 546 | require.alias("component-event/index.js", "list.pagination.js/deps/event/index.js"); 547 | require.alias("component-event/index.js", "event/index.js"); 548 | 549 | require.alias("component-indexof/index.js", "list.pagination.js/deps/indexof/index.js"); 550 | require.alias("component-indexof/index.js", "indexof/index.js"); 551 | 552 | require.alias("list.pagination.js/index.js", "list.pagination.js/index.js");if (typeof exports == "object") { 553 | module.exports = require("list.pagination.js"); 554 | } else if (typeof define == "function" && define.amd) { 555 | define(function(){ return require("list.pagination.js"); }); 556 | } else { 557 | this["ListPagination"] = require("list.pagination.js"); 558 | }})(); -------------------------------------------------------------------------------- /www-data/js/vendor/modernizr-2.6.1-respond-1.1.0.min.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.6.1 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),k.id=h,(l?k:m).innerHTML+=f,m.appendChild(k),l||(m.style.background="",g.appendChild(m)),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(['#modernizr:after{content:"',l,'";visibility:hidden}'].join(""),function(b){a=b.offsetHeight>=1}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&o.call(a.opera)=="[object Opera]",l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f #mq-test-1 { width: 42px; }';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document); 9 | 10 | /*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 11 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this); -------------------------------------------------------------------------------- /www-data/playbooks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ansible Dashr - 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 |
      33 | 45 |
      46 |
      47 |

      Playbooks

      48 | 49 | 52 |
      53 |
      54 | 55 | 56 | 57 |

      {{PlaybookName}}

      58 |
      59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
      Playbook View
      Playbook:Role
      {{PlaybookName: Role}}
      71 |
      72 |
      73 | 74 | 77 |
      78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /www-data/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /www-data/roles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Roles - Ansible Dashr 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 |
      33 | 45 |
      46 |
      47 |

      Roles

      48 | 49 | 52 |
      53 |
      54 | 55 | 56 | 57 |

      {{RoleName}}

      58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
      Role View
      Tasks
      {{List of Tasks in good view.}}
      70 |
      71 |
      72 | 73 | 76 |
      77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /www-data/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Ansible Dashr - 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 |
      32 | 44 |
      45 |
      46 |

      {{ Form help runner command formation. }}

      47 | 48 |
      49 |
      50 | 51 | 54 |
      55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | --------------------------------------------------------------------------------