Skip to content
Snippets Groups Projects
Commit 9987d724 authored by Remy Mudingay's avatar Remy Mudingay :speech_balloon:
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 494 additions and 0 deletions
[flake8]
ignore = E501
.molecule
.vagrant
.cache
*.swp
.DS_Store
__pycache__
*.pyc
extends: default
rules:
braces:
max-spaces-inside: 1
level: error
brackets:
max-spaces-inside: 1
level: error
line-length: disable
# NOTE(retr0h): Templates no longer fail this lint rule.
# Uncomment if running old Molecule templates.
# truthy: disable
LICENSE 0 → 100644
BSD 2-Clause License
Copyright (c) 2018, European Spallation Source ERIC
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ics-ans-role-tinyproxy
======================
Ansible role to install ics-ans-role-tinyproxy.
Tinyproxy can proxy both HTTP and HTTPS (ssl) traffic.
Note that the CONNECT based tunnel is used SSL traffic and uses a domain
blacklist or whitelist to filter destinations.
HTTP traffic can be filtered at the url level and suports regex expressions.
Requirements
------------
- ansible >= 2.3
- molecule >= 2.0
Role Variables
----------
Modify defaults/main.yml
```yaml
#LogLevel to configure
tinyproxy_log_level: [default: Info]
#Limit number of clients connected to Tinyproxy simultaneously
tinyproxy_maxclients: [default: 100]
#Minimum number of processes waiting for new users
tinyproxy_minspare_servers: [default: 5]
#Maximum number of processes waiting for users
tinyproxy_maxspare_servers: [default: 10]
#Number of childs to start at begining
tinyproxy_startservers: [default: 10]
#Limit number of requests per client
tinyproxy_maxrequest: [default: 0]
#Define a list of subnets that are allowed to use proxy
tinyproxy_allowed_subnet:
#Deny access from a list of subnet
tinyproxy_denied_subnet: [default: None]
#IP address to bind to
tinyproxy_listen_address: [default: 0.0.0.0]
#Port for tinyproxy to listen on
tinyproxy_port: [default: 8888]
#Define a list of urls (http) and domains (https) that clients can access (whitelist)
tinyproxy_urls:
#Setup Tinyproxy filtering rules
tinyproxy_filtering:
filter: "/etc/tinyproxy/filter"
urls: On
extended: On
#If set to Off, then the tinyproxy_url list becomes a blacklist (clients can not access)
default_deny: On
case_sensitive: Off
#List of upstream proxies to use
tinyproxy_upstream_proxies: [default: []]
#Address of upstream proxy in form host:port
tinyproxy_upstream_proxies.{n}.address: [required]:
#Optional URLs for which we want to use upstream proxy for.
tinyproxy_upstream_proxies.{n}.url: [optional]:
```
Example playbook
----------------
```yaml
- hosts: servers
roles:
- role: ics-ans-role-dns
```
License
-------
BSD 2-clause
---
tinyproxy_log_level: Info
tinyproxy_maxclients: 100
tinyproxy_minspare_servers: 5
tinyproxy_maxspare_servers: 10
tinyproxy_startservers: 10
tinyproxy_maxrequest: 0
tinyproxy_allowed_subnets: []
# - 0.0.0.0
tinyproxy_denied_subnets: []
tinyproxy_listen_addresses:
- 0.0.0.0
tinyproxy_port: 8888
tinyproxy_upstream_proxies: []
tinyproxy_connect_ports: []
tinyproxy_urls: []
tinyproxy_filtering:
filter: "/etc/tinyproxy/filter"
urls: "On"
extended: "On"
default_deny: "On"
case_sensitive: "Off"
epel_repo_url: "https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ ansible_distribution_major_version }}.noarch.rpm"
epel_repo_gpg_key_url: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-{{ ansible_distribution_major_version }}"
epel_repofile_path: "/etc/yum.repos.d/epel.repo"
---
- name: restart tinyproxy
become: "yes"
service:
name: tinyproxy
state: restarted
---
galaxy_info:
author: Remy Mudingay
company: European Spallation Source ERIC
description: Ansible role to install tinyproxy.
license: BSD
min_ansible_version: 2.3
platforms:
- name: CentOS
versions:
- 7
dependencies: []
# List your role dependencies here, one per line.
# Be sure to remove the '[]' above if you add dependencies
# to this list.
# Molecule managed
{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}
RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get upgrade -y && apt-get install -y python sudo bash ca-certificates && apt-get clean; \
elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python2-dnf bash && dnf clean all; \
elif [ $(command -v yum) ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \
elif [ $(command -v zypper) ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash python-xml && zypper clean -a; \
elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; fi
---
- name: Create
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}"
vars:
molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}"
molecule_instance_config: "{{ lookup('env', 'MOLECULE_INSTANCE_CONFIG') }}"
molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}"
tasks:
- name: Create molecule instance(s)
molecule_vagrant:
instance_name: "{{ item.name }}"
instance_interfaces: "{{ item.interfaces | default(omit) }}"
instance_raw_config_args: "{{ item.instance_raw_config_args | default(omit) }}"
platform_box: "{{ item.box }}"
platform_box_version: "{{ item.box_version | default(omit) }}"
platform_box_url: "{{ item.box_url | default(omit) }}"
provider_name: "{{ molecule_yml.driver.provider.name }}"
provider_memory: "{{ item.memory | default(omit) }}"
provider_cpus: "{{ item.cpus | default(omit) }}"
provider_raw_config_args: "{{ item.raw_config_args | default(omit) }}"
provision: "{{ item.provision | default(omit) }}"
state: up
register: server
with_items: "{{ molecule_yml.platforms }}"
# NOTE(retr0h): Vagrant/VBox sucks and parallelizing instance creation
# causes issues.
# Mandatory configuration for Molecule to function.
- name: Populate instance config dict
set_fact:
instance_conf_dict: {
'instance': "{{ item.Host }}",
'address': "{{ item.HostName }}",
'user': "{{ item.User }}",
'port': "{{ item.Port }}",
'identity_file': "{{ item.IdentityFile }}", }
with_items: "{{ server.results }}"
register: instance_config_dict
when: server.changed | bool
- name: Convert instance config dict to a list
set_fact:
instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}"
when: server.changed | bool
- name: Dump instance config
copy:
# NOTE(retr0h): Workaround for Ansible 2.2.
# https://github.com/ansible/ansible/issues/20885
content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}"
dest: "{{ molecule_instance_config }}"
when: server.changed | bool
---
- name: Destroy
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}"
vars:
molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}"
molecule_instance_config: "{{ lookup('env',' MOLECULE_INSTANCE_CONFIG') }}"
molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}"
tasks:
- name: Destroy molecule instance(s)
molecule_vagrant:
instance_name: "{{ item.name }}"
platform_box: "{{ item.box }}"
provider_name: "{{ molecule_yml.driver.provider.name }}"
force_stop: "{{ item.force_stop | default(true) }}"
state: destroy
register: server
with_items: "{{ molecule_yml.platforms }}"
# NOTE(retr0h): Vagrant/VBox sucks and parallelizing instance deletion
# causes issues.
# Mandatory configuration for Molecule to function.
- name: Populate instance config
set_fact:
instance_conf: {}
- name: Dump instance config
copy:
# NOTE(retr0h): Workaround for Ansible 2.2.
# https://github.com/ansible/ansible/issues/20885
content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}"
dest: "{{ molecule_instance_config }}"
when: server.changed | bool
---
dependency:
name: galaxy
lint:
name: yamllint
provisioner:
name: ansible
lint:
name: ansible-lint
inventory:
group_vars:
default_group:
scenario:
name: default
verifier:
name: testinfra
lint:
name: flake8
driver:
name: vagrant
provider:
name: virtualbox
platforms:
- name: ics-ans-role-tinyproxy-default
box: centos/7
memory: 512
cpus: 1
instance_raw_config_args:
- "vbguest.auto_update = false"
groups:
- default_group
---
dependency:
name: galaxy
lint:
name: yamllint
provisioner:
name: ansible
lint:
name: ansible-lint
inventory:
group_vars:
default_group:
scenario:
name: default
verifier:
name: testinfra
lint:
name: flake8
driver:
name: docker
platforms:
- name: ics-ans-role-tinyproxy-default
image: centos:7
groups:
- default_group
---
- name: Converge
hosts: all
become: true
roles:
- role: ics-ans-role-tinyproxy
---
- name: Prepare
hosts: all
gather_facts: false
tasks:
- name: Install python for Ansible
raw: test -e /usr/bin/python || (apt -y update && apt install -y python-minimal)
become: true
changed_when: false
import os
import testinfra.utils.ansible_runner
import testinfra
import unittest
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
#def test_default(host):
# TODO: implement at least a test
#assert False
def test_tinyproxy_is_installed(Package):
tinyproxy = Package("tinyproxy")
assert tinyproxy.is_installed
assert tinyproxy.version.startswith("1.8.3")
---
- name: Check if EPEL repo is already configured.
stat:
path: "{{ epel_repofile_path }}"
register: epel_repofile_result
- name: Install EPEL repo.
yum:
name: "{{ epel_repo_url }}"
state: present
register: result
when: not epel_repofile_result.stat.exists
- name: Import EPEL GPG key.
rpm_key:
key: "{{ epel_repo_gpg_key_url }}"
state: present
when: not epel_repofile_result.stat.exists
- name: Install tinyproxy
become: "yes"
yum:
name: tinyproxy
state: present
- name: Copy 400 error html files
become: "yes"
template:
src: ../templates/400.html
dest: /usr/share/tinyproxy/400.html
- name: Copy 403 error html files
become: "yes"
template:
src: ../templates/403.html
dest: /usr/share/tinyproxy/403.html
- name: Copy 404 error html files
become: "yes"
template:
src: ../templates/404.html
dest: /usr/share/tinyproxy/404.html
- name: Copy 503 error html files
become: "yes"
template:
src: ../templates/503.html
dest: /usr/share/tinyproxy/503.html
- name: Create url filter file for tinyproxy
become: "yes"
template:
src: ../templates/filter.j2
dest: /etc/tinyproxy/filter
notify:
- restart tinyproxy
- name: Setup configuration file for tinyproxy
become: "yes"
template:
src: ../templates/tinyproxy.conf.j2
dest: /etc/tinyproxy/tinyproxy.conf
notify:
- restart tinyproxy
- name: Test that tinyproxy is up
become: "yes"
service:
enabled: "yes"
name: tinyproxy
changed_when: "False"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>We've got some trouble | 400 - Bad Request</title>
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */body,html{width:100%;height:100%;background-color:#21232a}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:silver;font-size:21px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}</style>
</head>
<body>
<div class="cover"><h1>Bad Request <small>Error 400</small></h1><p class="lead">The server cannot process the request due to something that is perceived to be a client error.</p></div>
<footer><p>Technical Contact: <a href="https://jira.esss.lu.se/projects/INFRA/">INFRA_on_JIRA</a></p></footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>We've got some trouble | 403 - Access Denied</title>
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */body,html{width:100%;height:100%;background-color:#21232a}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:silver;font-size:21px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}</style>
</head>
<body>
<div class="cover"><h1>Access Denied <small>Error 403</small></h1><p class="lead">The requested resource requires an authentication.</p></div>
<footer><p>Technical Contact: <a href="https://jira.esss.lu.se/projects/INFRA/">INFRA_on_JIRA</a></p></footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>We've got some trouble | 404 - Resource not found</title>
<style type="text/css">/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | https://github.com/AndiDittrich/HttpErrorPages */body,html{width:100%;height:100%;background-color:#21232a}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:silver;font-size:21px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}</style>
</head>
<body>
<div class="cover"><h1>Resource not found <small>Error 404</small></h1><p class="lead">The requested resource could not be found but may be available again in the future.</p></div>
<footer><p>Technical Contact: <a href="https://jira.esss.lu.se/projects/INFRA/">INFRA_on_JIRA</a></p></footer>
</body>
</html>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment