diff --git a/rudder-server-relay/SOURCES/.dependencies b/rudder-server-relay/.dependencies similarity index 100% rename from rudder-server-relay/SOURCES/.dependencies rename to rudder-server-relay/.dependencies diff --git a/rudder-server-relay/SOURCES/Makefile b/rudder-server-relay/SOURCES/Makefile deleted file mode 100644 index 2256bee17..000000000 --- a/rudder-server-relay/SOURCES/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -##################################################################################### -# Copyright 2011 Normation SAS -##################################################################################### -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, Version 3. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -##################################################################################### - -.DEFAULT_GOAL := localdepends - -RUDDER_VERSION_TO_PACKAGE = -VIRTUALENV_RELEASE = 16.0.0 -VIRTUALENV_SHA256 = ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752 - -# GENERIC_GET: do not remove this line -# This is a generic get code that is common to many of our Makefiles. -# The tag is here to find them. Rudder agent has an even more generic one. -# If you change this code, change all the places where you can find this tag too. -# It is duplicated because it is the code that is used to manage dependency -# to other repositories, hence allowing deduplication of other code. -# Autodetect wget, curl or fetch usage and proxy configuration -# Usage: $(GET) -PROXY_ENV = $(if $(PROXY), http_proxy=$(PROXY) ftp_proxy=$(PROXY)) -# No accept encoding to prevent the webserver form altering the distributed file -WGET = wget -q --header="accept-encoding:" -O -CURL = curl -s --http1.1 -L -o -ifneq (,$(wildcard /usr/bin/curl)) -_GET = $(PROXY_ENV) $(CURL) -else -_GET = $(PROXY_ENV) $(WGET) -endif -# Pass an empty string to skip hash check -GET=get() { $(_GET) "$$1.part" "$$2" && { openssl dgst -sha256 "$$1.part" | grep -q "$$3" || { echo "Wrong checksum, aborting"; exit 1; }; } && mv "$$1.part" "$$1"; }; get - -localdepends: ./rudder-sources ./relay-api/virtualenv/virtualenv.py - -./rudder-sources.tar.bz2: - $(GET) rudder-sources.tar.bz2 https://www.rudder-project.org/archives/rudder-sources-${RUDDER_VERSION_TO_PACKAGE}.tar.bz2 "" - -./rudder-sources: ./rudder-sources.tar.bz2 - tar -xjf rudder-sources.tar.bz2 - mv rudder-sources-*/ rudder-sources/ - -./relay-api/virtualenv.tgz: /usr/bin/wget - # Original URL: https://pypi.python.org/packages/source/v/virtualenv/virtualenv-12.0.7.tar.gz - $(GET) relay-api/virtualenv.tgz https://repository.rudder.io/build-dependencies/virtualenv/virtualenv-$(VIRTUALENV_RELEASE).tar.gz $(VIRTUALENV_SHA256) - -./relay-api/virtualenv/virtualenv.py: ./relay-api/virtualenv.tgz - cd relay-api && tar -xzf ./virtualenv.tgz - cd relay-api && mv ./virtualenv-$(VIRTUALENV_RELEASE)/ virtualenv/ - -localclean: - rm -rf ./rudder-sources - -veryclean: - rm -f ./rudder-sources.tar.bz2 - -.PHONY: localdepends localclean veryclean diff --git a/rudder-server-relay/SOURCES/docopt.py b/rudder-server-relay/SOURCES/docopt.py deleted file mode 100644 index 7b927e2f8..000000000 --- a/rudder-server-relay/SOURCES/docopt.py +++ /dev/null @@ -1,579 +0,0 @@ -"""Pythonic command-line interface parser that will make you smile. - - * http://docopt.org - * Repository and issue-tracker: https://github.com/docopt/docopt - * Licensed under terms of MIT license (see LICENSE-MIT) - * Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com - -""" -import sys -import re - - -__all__ = ['docopt'] -__version__ = '0.6.2' - - -class DocoptLanguageError(Exception): - - """Error in construction of usage-message by developer.""" - - -class DocoptExit(SystemExit): - - """Exit in case user invoked program with incorrect arguments.""" - - usage = '' - - def __init__(self, message=''): - SystemExit.__init__(self, (message + '\n' + self.usage).strip()) - - -class Pattern(object): - - def __eq__(self, other): - return repr(self) == repr(other) - - def __hash__(self): - return hash(repr(self)) - - def fix(self): - self.fix_identities() - self.fix_repeating_arguments() - return self - - def fix_identities(self, uniq=None): - """Make pattern-tree tips point to same object if they are equal.""" - if not hasattr(self, 'children'): - return self - uniq = list(set(self.flat())) if uniq is None else uniq - for i, c in enumerate(self.children): - if not hasattr(c, 'children'): - assert c in uniq - self.children[i] = uniq[uniq.index(c)] - else: - c.fix_identities(uniq) - - def fix_repeating_arguments(self): - """Fix elements that should accumulate/increment values.""" - either = [list(c.children) for c in self.either.children] - for case in either: - for e in [c for c in case if case.count(c) > 1]: - if type(e) is Argument or type(e) is Option and e.argcount: - if e.value is None: - e.value = [] - elif type(e.value) is not list: - e.value = e.value.split() - if type(e) is Command or type(e) is Option and e.argcount == 0: - e.value = 0 - return self - - @property - def either(self): - """Transform pattern into an equivalent, with only top-level Either.""" - # Currently the pattern will not be equivalent, but more "narrow", - # although good enough to reason about list arguments. - ret = [] - groups = [[self]] - while groups: - children = groups.pop(0) - types = [type(c) for c in children] - if Either in types: - either = [c for c in children if type(c) is Either][0] - children.pop(children.index(either)) - for c in either.children: - groups.append([c] + children) - elif Required in types: - required = [c for c in children if type(c) is Required][0] - children.pop(children.index(required)) - groups.append(list(required.children) + children) - elif Optional in types: - optional = [c for c in children if type(c) is Optional][0] - children.pop(children.index(optional)) - groups.append(list(optional.children) + children) - elif AnyOptions in types: - optional = [c for c in children if type(c) is AnyOptions][0] - children.pop(children.index(optional)) - groups.append(list(optional.children) + children) - elif OneOrMore in types: - oneormore = [c for c in children if type(c) is OneOrMore][0] - children.pop(children.index(oneormore)) - groups.append(list(oneormore.children) * 2 + children) - else: - ret.append(children) - return Either(*[Required(*e) for e in ret]) - - -class ChildPattern(Pattern): - - def __init__(self, name, value=None): - self.name = name - self.value = value - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value) - - def flat(self, *types): - return [self] if not types or type(self) in types else [] - - def match(self, left, collected=None): - collected = [] if collected is None else collected - pos, match = self.single_match(left) - if match is None: - return False, left, collected - left_ = left[:pos] + left[pos + 1:] - same_name = [a for a in collected if a.name == self.name] - if type(self.value) in (int, list): - if type(self.value) is int: - increment = 1 - else: - increment = ([match.value] if type(match.value) is str - else match.value) - if not same_name: - match.value = increment - return True, left_, collected + [match] - same_name[0].value += increment - return True, left_, collected - return True, left_, collected + [match] - - -class ParentPattern(Pattern): - - def __init__(self, *children): - self.children = list(children) - - def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, - ', '.join(repr(a) for a in self.children)) - - def flat(self, *types): - if type(self) in types: - return [self] - return sum([c.flat(*types) for c in self.children], []) - - -class Argument(ChildPattern): - - def single_match(self, left): - for n, p in enumerate(left): - if type(p) is Argument: - return n, Argument(self.name, p.value) - return None, None - - @classmethod - def parse(class_, source): - name = re.findall('(<\S*?>)', source)[0] - value = re.findall('\[default: (.*)\]', source, flags=re.I) - return class_(name, value[0] if value else None) - - -class Command(Argument): - - def __init__(self, name, value=False): - self.name = name - self.value = value - - def single_match(self, left): - for n, p in enumerate(left): - if type(p) is Argument: - if p.value == self.name: - return n, Command(self.name, True) - else: - break - return None, None - - -class Option(ChildPattern): - - def __init__(self, short=None, long=None, argcount=0, value=False): - assert argcount in (0, 1) - self.short, self.long = short, long - self.argcount, self.value = argcount, value - self.value = None if value is False and argcount else value - - @classmethod - def parse(class_, option_description): - short, long, argcount, value = None, None, 0, False - options, _, description = option_description.strip().partition(' ') - options = options.replace(',', ' ').replace('=', ' ') - for s in options.split(): - if s.startswith('--'): - long = s - elif s.startswith('-'): - short = s - else: - argcount = 1 - if argcount: - matched = re.findall('\[default: (.*)\]', description, flags=re.I) - value = matched[0] if matched else None - return class_(short, long, argcount, value) - - def single_match(self, left): - for n, p in enumerate(left): - if self.name == p.name: - return n, p - return None, None - - @property - def name(self): - return self.long or self.short - - def __repr__(self): - return 'Option(%r, %r, %r, %r)' % (self.short, self.long, - self.argcount, self.value) - - -class Required(ParentPattern): - - def match(self, left, collected=None): - collected = [] if collected is None else collected - l = left - c = collected - for p in self.children: - matched, l, c = p.match(l, c) - if not matched: - return False, left, collected - return True, l, c - - -class Optional(ParentPattern): - - def match(self, left, collected=None): - collected = [] if collected is None else collected - for p in self.children: - m, left, collected = p.match(left, collected) - return True, left, collected - - -class AnyOptions(Optional): - - """Marker/placeholder for [options] shortcut.""" - - -class OneOrMore(ParentPattern): - - def match(self, left, collected=None): - assert len(self.children) == 1 - collected = [] if collected is None else collected - l = left - c = collected - l_ = None - matched = True - times = 0 - while matched: - # could it be that something didn't match but changed l or c? - matched, l, c = self.children[0].match(l, c) - times += 1 if matched else 0 - if l_ == l: - break - l_ = l - if times >= 1: - return True, l, c - return False, left, collected - - -class Either(ParentPattern): - - def match(self, left, collected=None): - collected = [] if collected is None else collected - outcomes = [] - for p in self.children: - matched, _, _ = outcome = p.match(left, collected) - if matched: - outcomes.append(outcome) - if outcomes: - return min(outcomes, key=lambda outcome: len(outcome[1])) - return False, left, collected - - -class TokenStream(list): - - def __init__(self, source, error): - self += source.split() if hasattr(source, 'split') else source - self.error = error - - def move(self): - return self.pop(0) if len(self) else None - - def current(self): - return self[0] if len(self) else None - - -def parse_long(tokens, options): - """long ::= '--' chars [ ( ' ' | '=' ) chars ] ;""" - long, eq, value = tokens.move().partition('=') - assert long.startswith('--') - value = None if eq == value == '' else value - similar = [o for o in options if o.long == long] - if tokens.error is DocoptExit and similar == []: # if no exact match - similar = [o for o in options if o.long and o.long.startswith(long)] - if len(similar) > 1: # might be simply specified ambiguously 2+ times? - raise tokens.error('%s is not a unique prefix: %s?' % - (long, ', '.join(o.long for o in similar))) - elif len(similar) < 1: - argcount = 1 if eq == '=' else 0 - o = Option(None, long, argcount) - options.append(o) - if tokens.error is DocoptExit: - o = Option(None, long, argcount, value if argcount else True) - else: - o = Option(similar[0].short, similar[0].long, - similar[0].argcount, similar[0].value) - if o.argcount == 0: - if value is not None: - raise tokens.error('%s must not have an argument' % o.long) - else: - if value is None: - if tokens.current() is None: - raise tokens.error('%s requires argument' % o.long) - value = tokens.move() - if tokens.error is DocoptExit: - o.value = value if value is not None else True - return [o] - - -def parse_shorts(tokens, options): - """shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;""" - token = tokens.move() - assert token.startswith('-') and not token.startswith('--') - left = token.lstrip('-') - parsed = [] - while left != '': - short, left = '-' + left[0], left[1:] - similar = [o for o in options if o.short == short] - if len(similar) > 1: - raise tokens.error('%s is specified ambiguously %d times' % - (short, len(similar))) - elif len(similar) < 1: - o = Option(short, None, 0) - options.append(o) - if tokens.error is DocoptExit: - o = Option(short, None, 0, True) - else: # why copying is necessary here? - o = Option(short, similar[0].long, - similar[0].argcount, similar[0].value) - value = None - if o.argcount != 0: - if left == '': - if tokens.current() is None: - raise tokens.error('%s requires argument' % short) - value = tokens.move() - else: - value = left - left = '' - if tokens.error is DocoptExit: - o.value = value if value is not None else True - parsed.append(o) - return parsed - - -def parse_pattern(source, options): - tokens = TokenStream(re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source), - DocoptLanguageError) - result = parse_expr(tokens, options) - if tokens.current() is not None: - raise tokens.error('unexpected ending: %r' % ' '.join(tokens)) - return Required(*result) - - -def parse_expr(tokens, options): - """expr ::= seq ( '|' seq )* ;""" - seq = parse_seq(tokens, options) - if tokens.current() != '|': - return seq - result = [Required(*seq)] if len(seq) > 1 else seq - while tokens.current() == '|': - tokens.move() - seq = parse_seq(tokens, options) - result += [Required(*seq)] if len(seq) > 1 else seq - return [Either(*result)] if len(result) > 1 else result - - -def parse_seq(tokens, options): - """seq ::= ( atom [ '...' ] )* ;""" - result = [] - while tokens.current() not in [None, ']', ')', '|']: - atom = parse_atom(tokens, options) - if tokens.current() == '...': - atom = [OneOrMore(*atom)] - tokens.move() - result += atom - return result - - -def parse_atom(tokens, options): - """atom ::= '(' expr ')' | '[' expr ']' | 'options' - | long | shorts | argument | command ; - """ - token = tokens.current() - result = [] - if token in '([': - tokens.move() - matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token] - result = pattern(*parse_expr(tokens, options)) - if tokens.move() != matching: - raise tokens.error("unmatched '%s'" % token) - return [result] - elif token == 'options': - tokens.move() - return [AnyOptions()] - elif token.startswith('--') and token != '--': - return parse_long(tokens, options) - elif token.startswith('-') and token not in ('-', '--'): - return parse_shorts(tokens, options) - elif token.startswith('<') and token.endswith('>') or token.isupper(): - return [Argument(tokens.move())] - else: - return [Command(tokens.move())] - - -def parse_argv(tokens, options, options_first=False): - """Parse command-line argument vector. - - If options_first: - argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ; - else: - argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ; - - """ - parsed = [] - while tokens.current() is not None: - if tokens.current() == '--': - return parsed + [Argument(None, v) for v in tokens] - elif tokens.current().startswith('--'): - parsed += parse_long(tokens, options) - elif tokens.current().startswith('-') and tokens.current() != '-': - parsed += parse_shorts(tokens, options) - elif options_first: - return parsed + [Argument(None, v) for v in tokens] - else: - parsed.append(Argument(None, tokens.move())) - return parsed - - -def parse_defaults(doc): - # in python < 2.7 you can't pass flags=re.MULTILINE - split = re.split('\n *(<\S+?>|-\S+?)', doc)[1:] - split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])] - options = [Option.parse(s) for s in split if s.startswith('-')] - #arguments = [Argument.parse(s) for s in split if s.startswith('<')] - #return options, arguments - return options - - -def printable_usage(doc): - # in python < 2.7 you can't pass flags=re.IGNORECASE - usage_split = re.split(r'([Uu][Ss][Aa][Gg][Ee]:)', doc) - if len(usage_split) < 3: - raise DocoptLanguageError('"usage:" (case-insensitive) not found.') - if len(usage_split) > 3: - raise DocoptLanguageError('More than one "usage:" (case-insensitive).') - return re.split(r'\n\s*\n', ''.join(usage_split[1:]))[0].strip() - - -def formal_usage(printable_usage): - pu = printable_usage.split()[1:] # split and drop "usage:" - return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )' - - -def extras(help, version, options, doc): - if help and any((o.name in ('-h', '--help')) and o.value for o in options): - print(doc.strip("\n")) - sys.exit() - if version and any(o.name == '--version' and o.value for o in options): - print(version) - sys.exit() - - -class Dict(dict): - def __repr__(self): - return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items())) - - -def docopt(doc, argv=None, help=True, version=None, options_first=False): - """Parse `argv` based on command-line interface described in `doc`. - - `docopt` creates your command-line interface based on its - description that you pass as `doc`. Such description can contain - --options, , commands, which could be - [optional], (required), (mutually | exclusive) or repeated... - - Parameters - ---------- - doc : str - Description of your command-line interface. - argv : list of str, optional - Argument vector to be parsed. sys.argv[1:] is used if not - provided. - help : bool (default: True) - Set to False to disable automatic help on -h or --help - options. - version : any object - If passed, the object will be printed if --version is in - `argv`. - options_first : bool (default: False) - Set to True to require options preceed positional arguments, - i.e. to forbid options and positional arguments intermix. - - Returns - ------- - args : dict - A dictionary, where keys are names of command-line elements - such as e.g. "--verbose" and "", and values are the - parsed values of those elements. - - Example - ------- - >>> from docopt import docopt - >>> doc = ''' - Usage: - my_program tcp [--timeout=] - my_program serial [--baud=] [--timeout=] - my_program (-h | --help | --version) - - Options: - -h, --help Show this screen and exit. - --baud= Baudrate [default: 9600] - ''' - >>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30'] - >>> docopt(doc, argv) - {'--baud': '9600', - '--help': False, - '--timeout': '30', - '--version': False, - '': '127.0.0.1', - '': '80', - 'serial': False, - 'tcp': True} - - See also - -------- - * For video introduction see http://docopt.org - * Full documentation is available in README.rst as well as online - at https://github.com/docopt/docopt#readme - - """ - if argv is None: - argv = sys.argv[1:] - DocoptExit.usage = printable_usage(doc) - options = parse_defaults(doc) - pattern = parse_pattern(formal_usage(DocoptExit.usage), options) - # [default] syntax for argument is disabled - #for a in pattern.flat(Argument): - # same_name = [d for d in arguments if d.name == a.name] - # if same_name: - # a.value = same_name[0].value - argv = parse_argv(TokenStream(argv, DocoptExit), list(options), - options_first) - pattern_options = set(pattern.flat(Option)) - for ao in pattern.flat(AnyOptions): - doc_options = parse_defaults(doc) - ao.children = list(set(doc_options) - pattern_options) - #if any_options: - # ao.children += [Option(o.short, o.long, o.argcount) - # for o in argv if type(o) is Option] - extras(help, version, argv, doc) - matched, left, collected = pattern.fix().match(argv) - if matched and left == []: # better error message if left? - return Dict((a.name, a.value) for a in (pattern.flat() + collected)) - raise DocoptExit() diff --git a/rudder-server-relay/SOURCES/openssl.cnf b/rudder-server-relay/SOURCES/openssl.cnf deleted file mode 100644 index 8bc9ca849..000000000 --- a/rudder-server-relay/SOURCES/openssl.cnf +++ /dev/null @@ -1,28 +0,0 @@ -[ req ] -distinguished_name = req_distinguished_name - -[ req_distinguished_name ] - -[ server_cert ] - -# Self signed cert must be a CA to authenticate -basicConstraints = CA:TRUE - -# Client authentication and signature (deprecated) -#nsCertType = client, objsign - -# digitalSignature: to sign files (e.g. inventories) -# keyEncipherment: to cipher session keys (e.g. TLS session) -# dataEncipherment: to cipher files, mays be used some day -# keyCertSign: to sign certificate (as a CA or for self signed certs) -keyUsage = digitalSignature, keyEncipherment, dataEncipherment, keyCertSign - -# Optional, no generic signature usage, do not use -# clientAuth: for TLS communication -#extendedKeyUsage = clientAuth - -# PKIX recommendations -subjectKeyIdentifier=hash - -subjectAltName = $ENV::SUBJALTNAME - diff --git a/rudder-server-relay/SOURCES/relay-api/.gitignore b/rudder-server-relay/SOURCES/relay-api/.gitignore deleted file mode 100644 index a44542ded..000000000 --- a/rudder-server-relay/SOURCES/relay-api/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -flask -*.pyc diff --git a/rudder-server-relay/SOURCES/relay-api/README b/rudder-server-relay/SOURCES/relay-api/README deleted file mode 100644 index 29f2866cf..000000000 --- a/rudder-server-relay/SOURCES/relay-api/README +++ /dev/null @@ -1,41 +0,0 @@ -How to setup the API --------------------- - -Initialize the virtualenv with -$ ./virtualenv.py flask - -Activate the virtualenv -$ . flask/bin/activate - -Install dependencies -$ pip install -r requirements.txt - -Modify and include apache/relay-api.conf in your apache configuration - -How to test the shared-files API --------------------------------- - -Have a nodeslist.json in /var/rudder/cfengine-community/inputs/distributePolicy/1.0/nodeslist.json -Have a policy_server in /var/rudder/cfengine-community/policy_server.dat -Have a uuid file in /opt/rudder/etc/uuid.hive -Hase a key pair in /var/rudder/cfengine-community/ppkeys/localhost.{priv,pub} - -Launch a local API server -$ ./run.py - -Create a signature (you need a cfengine key) -$ /opt/rudder/bin/rudder-sign file - -Add the public key and TTL -$ echo pubkey=$(cat /var/rudder/cfengine-community/ppkeys/localhost.pub | grep -v -- -- | perl -pe 's/\n//g'i) >> file.sign -$ echo "ttl=1m" >> file.sign - -Create the data to send -$ echo "" | cat file.sign - file > putdata - -Send the data file -$ curl -T putdata http://127.0.0.1:5000/shared-files/target_uuid/source_uuid/filename - -Test a file presence -$ curl -w "%{http_code}\n" -X HEAD http://127.0.0.1:5000/shared-files/target_uuid/source_uuid/filename?hash=.... - diff --git a/rudder-server-relay/SOURCES/relay-api/apache/relay-api.wsgi b/rudder-server-relay/SOURCES/relay-api/apache/relay-api.wsgi deleted file mode 100644 index 28bb7b372..000000000 --- a/rudder-server-relay/SOURCES/relay-api/apache/relay-api.wsgi +++ /dev/null @@ -1,16 +0,0 @@ -# Import core modules -import sys - -# Set up paths -api_path = '/opt/rudder/share/relay-api' -virtualenv_path = '/opt/rudder/share/relay-api/flask' - -# Virtualenv initialization -activate_this = virtualenv_path + '/bin/activate_this.py' -execfile(activate_this, dict(__file__=activate_this)) - -# Append ncf API path to the current one -sys.path.append(api_path) - -# Launch -from relay_api import app as application diff --git a/rudder-server-relay/SOURCES/relay-api/cleanup.sh b/rudder-server-relay/SOURCES/relay-api/cleanup.sh deleted file mode 100755 index 8253e31f9..000000000 --- a/rudder-server-relay/SOURCES/relay-api/cleanup.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -# remove all files and their metadata in BASEDIR that have expired - -BASEDIR="/var/rudder/shared-files" -date=$(date +%s) -find "${BASEDIR}" -type f -name '*.metadata' | xargs grep -H 'expires=' | sed 's/^\(.*\).metadata:expires=/\1 /' | -while read f d -do - if [ ${date} -gt ${d} ] - then - rm "${f}" "${f}.metadata" - fi -done diff --git a/rudder-server-relay/SOURCES/relay-api/nodeslist.json.example b/rudder-server-relay/SOURCES/relay-api/nodeslist.json.example deleted file mode 100644 index 6a3283854..000000000 --- a/rudder-server-relay/SOURCES/relay-api/nodeslist.json.example +++ /dev/null @@ -1,22 +0,0 @@ -{ - "c5e38f75-3fbe-402f-ac78-4ada2ea784a5": { - "hostname": "host1.rudder.local", - "key-hash": "sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709", - "policy-server": "9b25d384-a0ed-4ac1-adf2-b5b0277a455d" - }, - "6b26bf62-fe19-45ba-a0bc-4a1ddeca52ef": { - "hostname": "host2.rudder.local", - "key-hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "policy-server": "9b25d384-a0ed-4ac1-adf2-b5b0277a455d" - }, - "465b0ed4-6cad-4dc3-a0ec-cf84c8e1d752": { - "hostname": "host3.rudder.local", - "key-hash": "sha512:cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", - "policy-server": "6b26bf62-fe19-45ba-a0bc-4a1ddeca52ef" - }, - "bf745c11-e995-4b4c-806a-86604708cfc3": { - "hostname": "host4.rudder.local", - "key-hash": "sha1:0539a3ee5e6b4b0d3255bfef95601890afd80710", - "policy-server": "465b0ed4-6cad-4dc3-a0ec-cf84c8e1d752" - } -} diff --git a/rudder-server-relay/SOURCES/relay-api/relay_api/__init__.py b/rudder-server-relay/SOURCES/relay-api/relay_api/__init__.py deleted file mode 100755 index b097c9768..000000000 --- a/rudder-server-relay/SOURCES/relay-api/relay_api/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from flask import Flask - -app = Flask(__name__) - -from relay_api import views diff --git a/rudder-server-relay/SOURCES/relay-api/relay_api/common.py b/rudder-server-relay/SOURCES/relay-api/relay_api/common.py deleted file mode 100644 index cb46ed033..000000000 --- a/rudder-server-relay/SOURCES/relay-api/relay_api/common.py +++ /dev/null @@ -1,60 +0,0 @@ -import traceback -import json -from flask import Flask, jsonify, request, abort, make_response - -NODES=None - - -# Format error as api output -def format_error(exception, debug): - message = "Internal error!\n" - message += "Cause: " + type(u'')(exception) + "\n" - if debug: - message += traceback.format_exc() + "\n" - error = make_response(message) - error.headers['Content-Type'] = 'text/plain; charset=utf-8' - error.status_code = 500 - return error - - -# Format a success response as api output -def format_response(text, code=200): - response = make_response(text) - response.headers['Content-Type'] = 'text/plain; charset=utf-8' - response.status_code = code - return response - - -# returns the UUID of localhost -def get_file_content(filename): - fd = open(filename, 'r') - content = fd.read().replace('\n','').strip() - fd.close() - return content - - -# returns [ relay_uuid, ... , node_uuid ], not including self -def node_route(nodes, my_uuid, uuid): - if uuid not in nodes: - raise ValueError("ERROR unknown node: " + str(uuid)) - if "policy-server" not in nodes[uuid]: - raise ValueError("ERROR invalid nodes file on the server for " + uuid) - server = nodes[uuid]["policy-server"] - if server == my_uuid: - return [uuid] - route = node_route(nodes, my_uuid, server) - route.append(uuid) - return route - - -# Returns the parsed content of the nodeslist file -def get_nodes_list(nodeslist_file): - global NODES - ## uncomment to enable nodeslist caching - #if NODES is not None: - # return NODES - fd = open(nodeslist_file, 'r') - NODES = json.load(fd) - fd.close() - return NODES - diff --git a/rudder-server-relay/SOURCES/relay-api/relay_api/remote_run.py b/rudder-server-relay/SOURCES/relay-api/relay_api/remote_run.py deleted file mode 100644 index 3fe768cb5..000000000 --- a/rudder-server-relay/SOURCES/relay-api/relay_api/remote_run.py +++ /dev/null @@ -1,201 +0,0 @@ -from relay_api.common import * - -import base64 -import re -import os -import datetime -import requests -from subprocess import Popen, PIPE, STDOUT -from flask import Flask, Response -import itertools - -# disable ssl warning on rudder connection in all the possible ways -try: - import urllib3 - urllib3.disable_warnings() -except: - pass - -try: - requests.packages.urllib3.disable_warnings() -except: - pass - -NEXTHOP = None -REMOTE_RUN_COMMAND = "sudo /opt/rudder/bin/rudder remote run" -LOCAL_RUN_COMMAND = "sudo /opt/rudder/bin/rudder agent run > /dev/null 2>&1" - -def get_next_hop(nodes, my_uuid): - """ Build a dict of node_id => nexthop_id """ - global NEXTHOP - ## uncomment to enable nexthop caching caching (depends on nodeslist caching) - #if NEXTHOP is not None: - # return NEXTHOP - #else: - NEXTHOP = {} - for node in nodes: - NEXTHOP[node] = node_route(nodes, my_uuid, node)[0] - return NEXTHOP - -def get_all_my_nodes(nexthop): - """ Get all my directly connected nodes """ - result = [] - for node in nexthop: - if nexthop[node] == node: - result.append(node) - return result - -def get_my_nodes(nexthop, nodes): - """ Get all nodes directly connected in the given list """ - result = [] - for node in nodes: - if node not in nexthop: - raise ValueError("ERROR unknown node: " + str(node)) - if nexthop[node] == node: - result.append(node) - return result - -def get_relay_nodes(nexthop, relay, nodes): - """ Get all nodes behind the given relay from the given list """ - result = [] - for node in nodes: - if node not in nexthop: - raise ValueError("ERROR unknown node: " + str(node)) - if nexthop[node] == relay and nexthop[node] != node: - result.append(node) - return result - -def get_next_relays(nexthop): - """ Get a list of all relays directly connected to me """ - result = set([]) - for node in nexthop: - next_hop = nexthop[node] - if next_hop != node: - result.add(next_hop) - return result - -def resolve_hostname(local_nodes, node): - """ Get the hostname of a node from its uuid """ - if node not in local_nodes: - raise ValueError("ERROR unknown node: " + str(node)) - if "hostname" not in local_nodes[node]: - raise ValueError("ERROR invalid nodes file on the server for " + node) - return local_nodes[node]["hostname"] - -def call_agent_run(host, uuid, classes, keep_output, asynchronous): - """ Call the run command locally """ - if classes: - classes_parameter = " -D " + classes - else: - classes_parameter = "" - - if uuid == "root": - # root cannot make a remote run call to itself (certificate is not recognized correctly) - # We do a standard local run instead. - command = LOCAL_RUN_COMMAND - else: - command = REMOTE_RUN_COMMAND - return run_command(command + classes_parameter + " " + host, uuid, keep_output, asynchronous) - -def run_command(command, prefix, keep_output, asynchronous): - """ Run the given command, prefixing all output lines with prefix """ - - if keep_output: - process = Popen(command, shell=True, stdout=PIPE, stderr=STDOUT) - if not asynchronous: - output = "".join([prefix + ":" + line for line in process.stdout.readlines()]) - process.wait() - else: - def stream(): - for line in iter(process.stdout.readline,''): - yield prefix + ":" + line.rstrip()+"\n" - output=stream() - else: - output = "" - process = Popen(command, shell=True) - if not asynchronous: - process.wait() - return output - -def make_api_call(host, nodes, all_nodes, classes, keep_output, asynchronous): - if all_nodes: - method = "all" - else: - method = "nodes" - - url = "https://" + host + "/rudder/relay-api/remote-run/" + method - - data = {} - - if classes: - data["classes"] = classes - - data["keep_output"] = keep_output - data["asynchronous"] = asynchronous - - if nodes: - data["nodes"] = ",".join(nodes) - - req = requests.post(url, data=data, verify=False, stream = asynchronous) - if req.status_code == 200: - response = "" - if asynchronous: - def stream(): - for content in req.iter_lines(): - yield content+"\n" - response = stream() - else: - response = req.text - return response - else: - raise ValueError("Upstream Error: " + req.text) - -def remote_run_generic(local_nodes, my_uuid, nodes, all_nodes, form): - # Set default option values - classes = None - keep_output = False - asynchronous = False - - if "classes" in form: - classes = form['classes'] - - if "keep_output" in form: - keep_output = form['keep_output'].lower() == "true" - - if "asynchronous" in form: - asynchronous = form['asynchronous'].lower() == "true" - - NEXTHOP = get_next_hop(local_nodes, my_uuid) - - def generate_output(): - result = [] - # Pass the call to sub relays - for relay in get_next_relays(NEXTHOP): - host = resolve_hostname(local_nodes, relay) - if all_nodes: - result.append(make_api_call(host, None, all_nodes, classes, keep_output, asynchronous)) - else: - relay_nodes = get_relay_nodes(NEXTHOP, relay, nodes) - if relay_nodes: - result.append(make_api_call(host, get_relay_nodes(NEXTHOP, relay, nodes), all_nodes, classes, keep_output, asynchronous)) - # Call directly managed nodes when needed - if all_nodes: - local_nodes_to_call = get_all_my_nodes(NEXTHOP) - else: - local_nodes_to_call = get_my_nodes(NEXTHOP, nodes) - for node in local_nodes_to_call: - host = resolve_hostname(local_nodes, node) - result.append( call_agent_run(host, node, classes, keep_output, asynchronous)) - return result - - # depending on wether we want an asynch result we need to do something different on the output - if asynchronous: - # An async response, we produce generators that will be the result of our various async calls - # We jsut need to chain them - # May be could mix them ? Don't know how ( pipe ? outputstream ? ) - response = itertools.chain(* generate_output()) - else: - # A synch response, we already have the final output and - response = "\n".join(generate_output()) - - return Response(response ) diff --git a/rudder-server-relay/SOURCES/relay-api/relay_api/shared_files.py b/rudder-server-relay/SOURCES/relay-api/relay_api/shared_files.py deleted file mode 100644 index 361a9628b..000000000 --- a/rudder-server-relay/SOURCES/relay-api/relay_api/shared_files.py +++ /dev/null @@ -1,334 +0,0 @@ -from relay_api.common import * - -import base64 -import re -import os -import datetime -import requests -import hashlib - -# disable ssl warning on rudder connection in all the possible ways -try: - import urllib3 - urllib3.disable_warnings() -except: - pass - -try: - from requests.packages import urllib3 - urllib3.disable_warnings() -except: - pass - -from pprint import pprint -from Crypto.Hash import SHA, SHA256, SHA512 -from Crypto.Signature import PKCS1_v1_5 -from Crypto.PublicKey import RSA - - -SIGNATURE_FORMAT="header=rudder-signature-v1" -METADATA_EXTENSION=".metadata" -BLOCKSIZE = 65536 -SHARED_FOLDER="/var/rudder/configuration-repository/shared-files" - -# convert a byte string to hexadecimal representation -toHex = lambda x:"".join([hex(ord(c))[2:].zfill(2) for c in x]) - -# convert an hexadecimal string to a byte string -toBin = lambda x:"".join([chr(int(x[c:c+2],16)) for c in range(0,len(x),2)]) - -# Parse a ttl string of the form "1day 2hours 3minute 4seconds" -# It can be abreviated to thos form "5h 3s" -# If it is a pure integer it is considered to be seconds -# Returns a timedelta object -def parse_ttl(string): - m = re.match(r'^\s*(\d+)\s*$', string) - if m: - days = 0 - seconds = int(m.group(1)) - else: - daymatch = r'(\d+)\s*d(?:ays?)?' - hourmatch = r'(\d+)\s*h(?:ours?)?' - minmatch = r'(\d+)\s*m(?:inutes?)?' - secmatch = r'(\d+)\s*s(?:econds?)?' - match = r'^\s*(?:' + daymatch + r')?\s*(?:' + hourmatch + r')?\s*(?:' + minmatch + r')?\s*(?:' + secmatch + r')?\s*$' - m = re.match(match, string) - if m: - days = 0 - seconds = 0 - if m.group(1) is not None: - days = int(m.group(1)) - if m.group(2) is not None: - seconds += 3600 * int(m.group(2)) - if m.group(3) is not None: - seconds += 60 * int(m.group(3)) - if m.group(4) is not None: - seconds += int(m.group(4)) - else: - raise ValueError("ERROR invalid TTL specification:" + string) - return datetime.timedelta(days, seconds) - - -# Extract the signature header from a data stream -# The header is delimited by an empty line -def get_header(data_stream): - # format parsing - line = data_stream.readline() - if line.rstrip() != SIGNATURE_FORMAT: - raise ValueError("ERROR unknown signature format: " + str(line)) - header = line - while True: - line = data_stream.readline() - if line == "\n": - return header - header += line - # the return is just above - - -# Extract informations from header -def parse_header(header): - data = {} - for line in header.rstrip().split("\n"): - m = re.match(r"(\w+)\s*=\s*(.*)", line) - if m: - data[m.group(1)] = m.group(2) - else: - raise ValueError("ERROR invalid format: " + line) - return data - - -# Extract a public key object from headers -def get_pubkey(header_info): - # validate header content first - if 'digest' not in header_info or 'short_pubkey' not in header_info: - raise ValueError("ERROR incomplete header, missing digest or public key") - pem = "-----BEGIN RSA PRIVATE KEY-----\n" + header_info['short_pubkey'] + "\n-----END RSA PRIVATE KEY-----\n" - return RSA.importKey(pem) - - -# Create expiry header line -def expiry_line(header_info, ttl_value): - if ttl_value is None or ttl_value == '': - if 'ttl' not in header_info: - raise ValueError("ERROR: No TTL provided") - ttl = parse_ttl(header_info['ttl']) - else: - ttl = parse_ttl(ttl_value) - expires = datetime.datetime.utcnow() + ttl # we take utcnow because we write a unix timestamp - delta = expires - datetime.datetime(1970, 1, 1) - timestamp = delta.days*24*3600 + delta.seconds # convert to unix timestamp - return "expires=" + str(timestamp) + "\n" - - -# Hash a message with a given algorithm -# Returns a hash object -def get_hash(algorithm, message): - if algorithm == "sha1": - h=SHA.new(message) - elif algorithm == "sha256": - h=SHA256.new(message) - elif algorithm == "sha512": - h=SHA512.new(message) - else: - raise ValueError("ERROR unknown key hash type: " + str(algorithm)) - return h - - -# Validate that a given public key matches the provided hash -# The public key is a key object and the hash is of the form 'algorithm:kex_value' -def validate_key(pubkey, keyhash): - try: - (keyhash_type, keyhash_value) = keyhash.split(":",1) - except: - raise ValueError("ERROR invalid key hash, it should be 'type:value': " + keyhash) - pubkey_bin = pubkey.exportKey(format="DER") - h = get_hash(keyhash_type, pubkey_bin) - return h.hexdigest() == keyhash_value - -# Validate that a message has been properly signed by the given key -# The public key is a key object, algorithm is the hash algorithm and digest the hex signature -# The key algorithm will always be RSA because is is loaded as such -# Returns a booleas for the validity and the message hash to avoid computing it twice -def validate_message(message, pubkey, algorithm, digest): - h = get_hash(algorithm, message) - cipher = PKCS1_v1_5.new(pubkey) - return (cipher.verify(h, toBin(digest)), h.hexdigest()) - - -# Find in which directory a shared file should be stored -def file_directory(shared_path, nodes, my_uuid, target_uuid, source_uuid, file_id): - if not re.match(r"^[\w\-.]+$", file_id): - raise ValueError("ERROR file_id must be an identifier [A-z0-9_-.]: " + str(file_id)) - route_path = '/shared-files/'.join(node_route(nodes, my_uuid, target_uuid)) - return shared_path + "/" + route_path + "/files/" + source_uuid - - -# Returns the stored hash from the metadata file -def get_metadata_hash(metadata_file): - fd = open(metadata_file, 'r') - line = fd.readline().rstrip() - if line != SIGNATURE_FORMAT: - fd.close() - raise ValueError("ERROR invalid storage: " + line) - while True: - line = fd.readline().rstrip() - m = re.match(r"(\w+)\s*=\s*(.*)", line) - if m: - if m.group(1) == "hash_value": - fd.close() - return m.group(2) - else: - fd.close() - raise ValueError("ERROR invalid storage: " + line) - -def get_shared_folder_hash(file_path, hasher): - with open(file_path, 'rb') as afile: - buf = afile.read(BLOCKSIZE) - while len(buf) > 0: - hasher.update(buf) - buf = afile.read(BLOCKSIZE) - return hasher.hexdigest() - -# ===================== -# Manage PUT API call -# ===================== -# Parameters: -# - target_uuid where to send the file to -# - source_uuid who sent the file -# - file_id under which name to store the file -# - data the file content -# - nodes the content of the nodes_list file -# - my_uuid uuid of the current relay (self) -# - shared_path the shared-files directory path -# - ttl duration to keep the file -# Returns the full path of the created file -def shared_files_put(target_uuid, source_uuid, file_id, data_stream, nodes, my_uuid, shared_path, ttl): - header = get_header(data_stream) - info = parse_header(header) - - # extract information - pubkey = get_pubkey(info) - if source_uuid not in nodes: - raise ValueError("ERROR unknown source node: " + str(source_uuid)) - if "key-hash" not in nodes[source_uuid]: - raise ValueError("ERROR invalid nodes file on the server for " + source_uuid) - keyhash = nodes[source_uuid]["key-hash"] - - # validate key - if not validate_key(pubkey, keyhash): - raise ValueError("ERROR invalid public key or not matching UUID") - - # validate message - message = data_stream.read() - (validated, message_hash) = validate_message(message, pubkey, info['algorithm'], info['digest']) - if not validated: - raise ValueError("ERROR invalid signature") - - # add headers - header += expiry_line(info, ttl) - # replace hash by a guaranteed one - header = re.sub(r'hash_value=.*?\n', "hash_value=" + message_hash + "\n", header) - - # where to store file - path = file_directory(shared_path, nodes, my_uuid, target_uuid, source_uuid, file_id) - filename = path + "/" + file_id - - # write data & metadata - try: - os.makedirs(path, 0o750) - except: - pass # makedirs fails if the directory exists - fd = open(filename, 'w') - fd.write(message) - fd.close() - fd = open(filename + METADATA_EXTENSION, 'w') - fd.write(header) - fd.close() - return filename - - -# ====================== -# Forward PUT API call -# ====================== -# Parameters: -# - stream stream of posted data -# - url where to forward to -# Returns the full path of the created file -def shared_files_put_forward(stream, url): - # This is needed to make requests know the length - # It will avoid streaming the content which would make the next hop fail - stream.len = stream.limit - req = requests.put(url, data=stream, verify=False) - if req.status_code == 200: - return req.text - else: - raise ValueError("Upstream Error: " + req.text) - -# ====================== -# Manage HEAD API call -# ====================== -# Parameters: -# - target_uuid where to send the file to -# - source_uuid who sent the file -# - file_id under which name to store the file -# - file_hash the hash to compare with -# - nodes the content of the nodes_list file -# - my_uuid uuid of the current relay (self) -# - shared_path the shared-files directory path -# Returns true of false -def shared_files_head(target_uuid, source_uuid, file_id, file_hash, nodes, my_uuid, shared_path): - # where to find file - path = file_directory(shared_path, nodes, my_uuid, target_uuid, source_uuid, file_id) - filename = path + "/" + file_id - metadata = filename + METADATA_EXTENSION - - # check if the file and signature exist - if not os.path.isfile(filename) or not os.path.isfile(metadata): - return False - - # check hash from metadata - hash_value = get_metadata_hash(metadata) - return hash_value == file_hash - -# ======================= -# Forward HEAD API call -# ======================= -# Parameters: -# - url where to forward to -# Returns true of false -def shared_files_head_forward(url): - req = requests.head(url, verify=False) - if req.status_code == 200: - return True - if req.status_code == 404: - return False - raise ValueError("ERROR from server:" + str(req.status_code)) - -# ====================== -# Share folder HEAD API call -# ====================== -# Parameters: -# - file_name Name of the file in shared folder -# - file_hash The hash to compare with, can be None or Empty -# - hash_type hash algorithm -# Returns correponding return code, 404 (file does not exists), 304 (hash is the same, not modified), 200 (file is different or no Hash sent, download) -# 500 if hash_type is invalid -def shared_folder_head(file_name, file_hash, hash_type): - # where to find file - file_path = os.path.join(SHARED_FOLDER, file_name) - # check if the file and signature exist - if not os.path.isfile(file_path): - return 404 - else: - if file_hash is None or file_hash == "": - return 200 - try: - hasher = hashlib.new(hash_type) - except: - return 500 - # check hash - hash_value = get_shared_folder_hash(file_path, hasher) - if hash_value == file_hash: - return 304 - else: - return 200 diff --git a/rudder-server-relay/SOURCES/relay-api/relay_api/views.py b/rudder-server-relay/SOURCES/relay-api/relay_api/views.py deleted file mode 100644 index 147400af4..000000000 --- a/rudder-server-relay/SOURCES/relay-api/relay_api/views.py +++ /dev/null @@ -1,134 +0,0 @@ -from relay_api import app -from relay_api.shared_files import shared_files_put, shared_files_head, shared_files_put_forward, shared_files_head_forward, shared_folder_head -from relay_api.remote_run import remote_run_generic -from relay_api.common import * - -from flask import Flask, jsonify, request, abort, make_response -try: - from StringIO import StringIO -except ImportError: - from io import StringIO -import traceback - -from pprint import pprint - -NODESLIST_FILE = "/opt/rudder/etc/nodeslist.json" -UUID_FILE = '/opt/rudder/etc/uuid.hive' -API_DEBUGINFO = True -POLICY_SERVER_FILE = "/var/rudder/cfengine-community/policy_server.dat" -SHARED_FILES_PATH = "/var/rudder/shared-files" - -################# -# API functions # -################# - -@app.route('/shared-files///', methods=['PUT']) -def put_file(target_uuid, source_uuid, file_id): - try: - nodes = get_nodes_list(NODESLIST_FILE) - ttl = request.args.get('ttl', '') - my_uuid = get_file_content(UUID_FILE) - if target_uuid not in nodes: - # forward the file if the node is unknown - if my_uuid == "root": - return format_response("Unknown UUID: "+target_uuid, 404) - else: - policy_server = get_file_content(POLICY_SERVER_FILE) - url = "https://"+policy_server+"/rudder/relay-api/shared-files/" + target_uuid + "/" + source_uuid + "/" + file_id + "?ttl=" + ttl - res = shared_files_put_forward(request.stream, url) - else: - # process the file if it is known - filename = shared_files_put(target_uuid, source_uuid, file_id, request.stream, nodes, my_uuid, SHARED_FILES_PATH, ttl) - if API_DEBUGINFO: - res = "OK\nWritten to: " + filename + "\n" - else: - res = "OK\n" - return format_response(res) - except Exception as e: - return format_error(e, API_DEBUGINFO) - -# mod_wsgi rewrites HEAD request to GET in some cases (don't know exactly when, but it depends on apache output filter, and breaks centos7 and not ubuntu 16) -# Broken with wod_wsgi 3.4, works with mod_wsgi 4.3.0 -# GET requests here a rewritten HEAD, Real GET while be send at another location by a rewrite (cond and rule in rudder-apache-relay-ssl.conf file) -# Some explanation: http://blog.dscpl.com.au/2009/10/wsgi-issues-with-http-head-requests.html -# Some workaround: https://github.com/GrahamDumpleton/mod_wsgi/issues/2 -@app.route("/shared-folder/", methods=["HEAD", "GET"]) -def head_shared_folder(file_name): - try: - hash_type = "sha256" - if "hash_type" in request.args: - hash_type = request.args["hash_type"] - file_hash = None - if "hash" in request.args: - file_hash = request.args["hash"] - return_code = shared_folder_head(file_name, file_hash, hash_type) - return format_response("", return_code) - - except Exception as e: - print(traceback.format_exc()) - return format_error(e, API_DEBUGINFO) - -# mod_wsgi rewrites HEAD request to GET in some cases (don't know exactly when, but it depends on apache output filter, and breaks centos7 and not ubuntu 16) -# Broken with wod_wsgi 3.2 and 3.4, works with mod_wsgi 4.3.0 -# GET requests here a rewritten HEAD, Real GET is never used on the shared-files api -# Some explanation: http://blog.dscpl.com.au/2009/10/wsgi-issues-with-http-head-requests.html -# Some workaround: https://github.com/GrahamDumpleton/mod_wsgi/issues/2 -@app.route('/shared-files///', methods=['HEAD','GET']) -def head_file(target_uuid, source_uuid, file_id): - try: - nodes = get_nodes_list(NODESLIST_FILE) - file_hash = request.args.get('hash', '') - my_uuid = get_file_content(UUID_FILE) - if target_uuid not in nodes: - # forward the request if the node is unknown - if my_uuid == "root": - return format_response("Unknown UUID: "+target_uuid, 404) - else: - policy_server = get_file_content(POLICY_SERVER_FILE) - url = "https://"+policy_server+"/rudder/relay-api/shared-files/" + target_uuid + "/" + source_uuid + "/" + file_id + "?hash=" + file_hash - res = shared_files_head_forward(url) - else: - # process the request if it is known - res = shared_files_head(target_uuid, source_uuid, file_id, file_hash, nodes, my_uuid, SHARED_FILES_PATH) - if res: - return format_response("", 200) - else: - return format_response("", 404) - except Exception as e: - print(traceback.format_exc()) - return format_error(e, API_DEBUGINFO) - -@app.route('/remote-run/all', methods=['POST']) -def remote_run_all(): - try: - nodes = get_nodes_list(NODESLIST_FILE) - my_uuid = get_file_content(UUID_FILE) - return remote_run_generic(nodes, my_uuid, None, True, request.form) - except Exception as e: - print(traceback.format_exc()) - return format_error(e, API_DEBUGINFO) - -@app.route('/remote-run/nodes', methods=['POST']) -def remote_run_nodes(): - try: - nodes = get_nodes_list(NODESLIST_FILE) - my_uuid = get_file_content(UUID_FILE) - return remote_run_generic(nodes, my_uuid, request.form['nodes'].split(','), False, request.form) - except Exception as e: - print(traceback.format_exc()) - return format_error(e, API_DEBUGINFO) - -@app.route('/remote-run/nodes/', methods=['POST']) -def remote_run_node(node_id): - try: - nodes = get_nodes_list(NODESLIST_FILE) - my_uuid = get_file_content(UUID_FILE) - return remote_run_generic(nodes, my_uuid, [node_id], False, request.form) - except Exception as e: - print(traceback.format_exc()) - return format_error(e, API_DEBUGINFO) - -# main -if __name__ == '__main__': - app.run(debug = True) - diff --git a/rudder-server-relay/SOURCES/relay-api/requirements.txt b/rudder-server-relay/SOURCES/relay-api/requirements.txt deleted file mode 100755 index 9a0599d42..000000000 --- a/rudder-server-relay/SOURCES/relay-api/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -flask==0.12.4 -requests==2.19.1 -pycrypto==2.6.1 diff --git a/rudder-server-relay/SOURCES/relay-api/run.py b/rudder-server-relay/SOURCES/relay-api/run.py deleted file mode 100755 index be8265d9e..000000000 --- a/rudder-server-relay/SOURCES/relay-api/run.py +++ /dev/null @@ -1,11 +0,0 @@ -#!flask/bin/python - -# This file is only present for development/ local test and should not be used in production -# To deploy ncf api you should use it with a virtual environment and a wsgi file -# an example of this is available in ncf-api-virualenv package -# Virtualenv defined should be in local directory flask - -import requests -from relay_api import app - -app.run(debug = True) diff --git a/rudder-server-relay/SOURCES/rudder-apache-relay-common.conf b/rudder-server-relay/SOURCES/rudder-apache-relay-common.conf deleted file mode 100644 index 8564c9edb..000000000 --- a/rudder-server-relay/SOURCES/rudder-apache-relay-common.conf +++ /dev/null @@ -1,105 +0,0 @@ -DocumentRoot /var/www - - - SSLOptions +StdEnvVars - - - SSLOptions +StdEnvVars - - -# We do not require mod_deflate as it is not strictly necessary - - - # Enable gzip encoding on textual resources - AddOutputFilterByType DEFLATE text/plain text/html text/xml text/javascript text/css - AddOutputFilterByType DEFLATE application/xml application/xhtml+xml application/rss+xml image/svg+xml - AddOutputFilterByType DEFLATE application/json application/javascript application/x-javascript - - - -# Expose the server UUID through http -Alias /uuid /opt/rudder/etc/uuid.hive - - Require all granted - - -# WebDAV share to receive inventories -Alias /inventories /var/rudder/inventories/incoming - - - DAV on - - AuthName "WebDAV Storage" - AuthType Basic - AuthUserFile /opt/rudder/etc/htpasswd-webdav-initial - - Require valid-user - - # rudder-networks-24.conf is automatically generated according to the hosts allowed by rudder. - Include /opt/rudder/etc/rudder-networks-24.conf - - - Require all denied - - - - -# WebDAV share to receive inventories -Alias /inventory-updates /var/rudder/inventories/accepted-nodes-updates - - - DAV on - - AuthName "WebDAV Storage" - AuthType Basic - AuthUserFile /opt/rudder/etc/htpasswd-webdav - - Require valid-user - - # rudder-networks-24.conf is automatically generated according to the hosts allowed by rudder. - Include /opt/rudder/etc/rudder-networks-24.conf - - - Require all denied - - - - -# Load relay-api -WSGIScriptAlias /rudder/relay-api /opt/rudder/share/relay-api/relay-api.wsgi - -## Set directory access permissions - - - # Allow access from anybody - Require all granted - - - - # Allow access from anybody - Require all granted - - - - # Allow access from anybody - Require all granted - - -# Disallow by default - - # WSGI parameters - WSGIProcessGroup relay_api - WSGIApplicationGroup %{GLOBAL} - - Require all denied - - - - # rudder-networks-24.conf is automatically generated according to the hosts allowed by rudder. - Include /opt/rudder/etc/rudder-networks-24.conf - - - - # rudder-networks-policy-server-24.conf is automatically generated according to the policy server defined in rudder. - Include /opt/rudder/etc/rudder-networks-policy-server-24.conf - diff --git a/rudder-server-relay/SOURCES/rudder-apache-relay-nossl.conf b/rudder-server-relay/SOURCES/rudder-apache-relay-nossl.conf deleted file mode 100644 index 74dbc0f9f..000000000 --- a/rudder-server-relay/SOURCES/rudder-apache-relay-nossl.conf +++ /dev/null @@ -1,11 +0,0 @@ -# Rudder webapp -RewriteEngine on - -# If we are not currently connected via HTTP/S -RewriteCond %{HTTPS} !=on - -# Restrict redirection to RudderRelay API -RewriteCond %{REQUEST_URI} ^/rudder/relay-api/? - -# Redirect to HTTPS -RewriteRule ^/(.*)$ https://%{SERVER_NAME}/$1 [R] diff --git a/rudder-server-relay/SOURCES/rudder-apache-relay-ssl.conf b/rudder-server-relay/SOURCES/rudder-apache-relay-ssl.conf deleted file mode 100644 index 1f5a89091..000000000 --- a/rudder-server-relay/SOURCES/rudder-apache-relay-ssl.conf +++ /dev/null @@ -1,46 +0,0 @@ -# Provide nodes policies -# ---------------------- - -RewriteEngine On - - -# List of allowed certificates -SSLCACertificateFile /opt/rudder/etc/ssl/ca.cert - -# Explanation -# 1. The Rewriterule pattern is matched -# Yes -> if so the result goes to $0,$1,$2 -# No -> no rewrite, no access to the files -# 2. The RewriteCond is checked -# -> Get client uuid from %{SSL:SSL_CLIENT_S_DN_UID} -# -> Get requested uuid from the Rewriterule pattern ($1) -# -> Generate a TestString of the form "=" -# -> Test the string against a regex that check that the left part is identical to the right part -# 3. The Rewriterule is applied -# -> final path is generated from the rule pattern -RewriteCond "%{SSL:SSL_CLIENT_S_DN_UID}=$1" "^(.*?)=\1" -RewriteRule /policies/(.*?)/(.*) /var/rudder/share/$1/$2 - -# This is the basic configuration for sub-directories of /var/rudder/share - - SSLVerifyClient require - SSLUserName SSL_CLIENT_S_DN_CN - SSLRequireSSL - - # rudder-networks-24.conf is automatically - # generated according to the hosts allowed by rudder. - Include /opt/rudder/etc/rudder-networks-24.conf - - - - - SSLVerifyClient require - SSLUserName SSL_CLIENT_S_DN_CN - SSLRequireSSL - - Include /opt/rudder/etc/rudder-networks-24.conf - - -RewriteCond %{REQUEST_METHOD} =GET -RewriteRule /rudder/relay-api/shared-folder/(.*) /var/rudder/configuration-repository/shared-files/$1 - diff --git a/rudder-server-relay/SOURCES/rudder-networks-24.conf b/rudder-server-relay/SOURCES/rudder-networks-24.conf deleted file mode 100644 index b66e80882..000000000 --- a/rudder-server-relay/SOURCES/rudder-networks-24.conf +++ /dev/null @@ -1 +0,0 @@ -Require all denied diff --git a/rudder-server-relay/SOURCES/rudder-networks-policy-server-24.conf b/rudder-server-relay/SOURCES/rudder-networks-policy-server-24.conf deleted file mode 100644 index 24968b58f..000000000 --- a/rudder-server-relay/SOURCES/rudder-networks-policy-server-24.conf +++ /dev/null @@ -1,2 +0,0 @@ -Require ip 127.0.0.0/8 -Require ip ::1 diff --git a/rudder-server-relay/SOURCES/rudder-pkg b/rudder-server-relay/SOURCES/rudder-pkg deleted file mode 100755 index 068cce8d0..000000000 --- a/rudder-server-relay/SOURCES/rudder-pkg +++ /dev/null @@ -1,416 +0,0 @@ -#!/usr/bin/python - -""" -Rudder package manager - -Usage: - rudder-pkg install-file ... - rudder-pkg list - rudder-pkg remove ... - rudder-pkg rudder-postupgrade - rudder-pkg check-compatibility - rudder-pkg plugin save-status - rudder-pkg plugin restore-status - rudder-pkg plugin enable ... - rudder-pkg plugin enable-all - rudder-pkg plugin disable ... - rudder-pkg plugin disable-all - -Options: - -Commands: - install-file - install a single package file into Rudder - - list - list installed packages - - remove - remove the given package from Rudder - - rudder-postupgrade - execute plugins post install scripts (needed after a Rudder upgrade) - - check-compatibility - disable plugins that are not compatible with current Rudder version - - plugin - commands on plugin status -""" - -# nice to have -# rudder-pkg install package # from std dir / from repo -# rudder-pkg upgrade package # from std dir / from repo - -from __future__ import print_function -import sys -sys.path.insert(0,"/opt/rudder/share/python") - -from pprint import pprint -import argparse -import json -import os -import tempfile -import shutil -import copy -import re -import docopt -import sys -import distutils.spawn -from subprocess import Popen,PIPE - -p = Popen("rudder agent version", shell=True, stdout=PIPE) -line = p.communicate()[0] -m = re.match(r'Rudder agent (\d+\.\d+)\..*', line.decode('utf-8')) -if m: - RUDDER_VERSION=m.group(1) -else: - print("Cannot retrieve major version, ABORTING !") - exit(1) -DB = { "plugins": { } } -DB_DIRECTORY = '/var/rudder/packages' -# Contains the installed package database -DB_FILE = DB_DIRECTORY + '/index.json' -# Contains known incompatible plugins (installed by the relay package) -# this is a simple list with names od the form "plugin_name-version" -COMPATIBILITY_DB = { "incompatibles": [] } -COMPATIBILITY_FILE = DB_DIRECTORY + '/compatible.json' - -# Plugins specific resources -PLUGINS_CONTEXT_XML = "/opt/rudder/share/webapps/rudder.xml" - - -# Run a command in a shell like a script would do -# And inform the user of its execution -def shell(command, comment=None, keep_output=False, fail_exit=True, keep_error=False): - if comment is not None: - print(comment) - print(" $ " + command) - if keep_output or keep_error: - if keep_output: - keep_out = PIPE - else: - keep_out = None - if keep_error: - keep_err = PIPE - else: - keep_err = None - process = Popen(command, stdout=keep_out, stderr=keep_err, shell=True, universal_newlines=True) - output, error = process.communicate() - retcode = process.poll() - else: # keep tty management and thus colors - process = Popen(command, shell=True) - retcode = process.wait() - output = None - error = None - if fail_exit and retcode != 0: - exit(retcode) - return (retcode, output, error) - - -def fail(message, code=1): - print(message) - exit(code) - - -# Indexing methods -def db_load(): - """ Load the index file into a global variable """ - global DB, COMPATIBILITY_DB - if os.path.isfile(DB_FILE): - with open(DB_FILE) as fd: - DB = json.load(fd) - if os.path.isfile(COMPATIBILITY_FILE): - with open(COMPATIBILITY_FILE) as fd: - COMPATIBILITY_DB = json.load(fd) - -def db_save(): - """ Save the index into a file """ - with open(DB_FILE, 'w') as fd: - json.dump(DB, fd) - - -def rpkg_metadata(package_file): - (_, output, _) = shell("ar p '" + package_file + "' metadata", keep_output=True) - return json.loads(output) - - -def package_check(metadata): - # we can only install pugins at the moment - if 'type' not in metadata or metadata['type'] != 'plugin': - fail("Package type not supported") - # sanity checks - if 'name' not in metadata: - fail("Package name undefined") - name = metadata['name'] - if 'version' not in metadata: - fail("Package version undefined") - # incompatibility check - if metadata['type'] == 'plugin': - if not check_plugin_compatibility(metadata): - fail("Package incompatible with this Rudder version, please use a more recent one") - # do not compare with exiting version to allow people to reinstall or downgrade - return name in DB['plugins'] - - -def check_plugin_compatibility(metadata): - # check that the given version is compatible with Rudder one - match = re.match(r'(\d+\.\d+)-(\d+)\.(\d+)', metadata['version']) - if not match: - fail("Invalid package version " + metadata['version']) - rudder_version = match.group(1) - major_version = match.group(2) - minor_version = match.group(3) - if rudder_version != RUDDER_VERSION: - print("Package '"+ metadata['name'] +"' is not compatible with current version of rudder") - return False - # check specific constraints - full_name = metadata['name'] + '-' + metadata['version'] - if full_name in COMPATIBILITY_DB['incompatibles']: - return False - return True - - - -def install_dependencies(metadata): - # not supported yet - has_depends = False - depends_printed = False - if "depends" in metadata: - for system in metadata["depends"]: - if system == "binary": - for executable in metadata["depends"][system]: - if distutils.spawn.find_executable(executable) is None: - print("The binary " + executable + " was not found on the system, you must install it before installing " + metadata['name']) - return False - else: - has_depends = True - if not depends_printed: - print("This package depends on the following") - depends_printed = True - print(" on " + system + " : " + ", ".join(metadata["depends"][system])) - if has_depends: - print("It is up to you to make sure those dependencies are installed") - return True - - -def extract_scripts(metadata,package_file): - package_dir = DB_DIRECTORY + "/" + metadata["name"] - shell("mkdir -p " + package_dir + "; ar p '" + package_file + "' scripts.txz | tar xJ --no-same-owner -C " + package_dir) - return package_dir - - -def run_script(name, script_dir, exist): - script = script_dir + "/" + name - if os.path.isfile(script): - if exist is None: - param = "" - elif exist: - param = "upgrade" - else: - param = "install" - shell(script + " " + param) - - -def jar_status(name, enable): - global jetty_needs_restart - text = open(PLUGINS_CONTEXT_XML).read() - def repl(match): - enabled = [x for x in match.group(1).split(',') if x != name and x != ''] - pprint(enabled) - if enable: - enabled.append(name) - plugins = ','.join(enabled) - return '' + plugins + '' - text = re.sub(r'(.*?)', repl, text) - open(PLUGINS_CONTEXT_XML, "w").write(text) - jetty_needs_restart = True - - -def remove_files(metadata): - for filename in reversed(metadata['files']): - # ignore already removed files - if not os.path.exists(filename): - print("Skipping removal of " + filename + " as it does not exist") - continue - - # remove old files - if filename.endswith('/'): - try: - os.rmdir(filename) - except OSError: - pass - else: - os.remove(filename) - - -def install(metadata, package_file, exist): - if exist: - remove_files(DB['plugins'][metadata['name']]) - # add new files - files = [] - for tarfile in metadata['content']: - dest = metadata['content'][tarfile] - (_, file_list, _) = shell("mkdir -p " + dest + "; ar p '" + package_file + "' " + tarfile + " | tar xJv --no-same-owner -C " + dest, keep_output=True) - files.append(dest+'/') - files.extend([ dest + '/' + x for x in file_list.split("\n") if x != '']) - - metadata['files'] = files - # update db - DB['plugins'][metadata['name']] = metadata - db_save() - - -## Package commands - -def install_file(package_files): - for package_file in package_files: - print("Installing " + package_file) - # First, check if file exists - if not os.path.isfile(package_file): - print("Error: Package file " + package_file + " does not exist") - exit(1) - metadata = rpkg_metadata(package_file) - exist = package_check(metadata) - # As dependencies are only displayed messages for now, wait until the end to make them visible. - # This should be moved before actual installation once implemented. - if not install_dependencies(metadata): - exit(1) - if exist: - print("The package is already installed, I will upgrade it.") - script_dir = extract_scripts(metadata, package_file) - run_script("preinst", script_dir, exist) - install(metadata, package_file, exist) - run_script("postinst", script_dir, exist) - if metadata['type'] == 'plugin' and 'jar-files' in metadata: - for j in metadata['jar-files']: - jar_status(j, True) - - -def package_list(): - for p in DB["plugins"].keys(): - print(p + "\t" + DB["plugins"][p]["version"]) - - -def remove(package_names): - for package_name in package_names: - print("Removing " + package_name) - if package_name not in DB["plugins"]: - fail("This package is not installed. Aborting!", 2) - script_dir = DB_DIRECTORY + "/" + package_name - metadata = DB["plugins"][package_name] - if metadata['type'] == 'plugin' and 'jar-files' in metadata: - for j in metadata['jar-files']: - jar_status(j, False) - run_script("prerm", script_dir, None) - remove_files(metadata) - run_script("postrm", script_dir, None) - shutil.rmtree(script_dir) - del DB["plugins"][package_name] - db_save() - - -def check_compatibility(): - global jetty_needs_restart - for p in DB["plugins"]: - metadata = DB["plugins"][p] - if not check_plugin_compatibility(metadata): - print("Plugin " + p + " is not compatible with rudder anymore, disabling it.") - if 'jar-files' in metadata: - for j in metadata['jar-files']: - jar_status(j, False) - print("Please install a new version of " + p + " to enable it again.") - print("") - jetty_needs_restart = True - - -def plugin_save_status(): - enabled = [] - - if not os.path.exists(PLUGINS_CONTEXT_XML): - return - - text = open(PLUGINS_CONTEXT_XML).read() - match = re.search(r'(.*?)', text) - if match: - enabled = match.group(1).split(',') - for p in DB["plugins"]: - metadata = DB["plugins"][p] - if 'jar-files' in metadata: - for j in metadata['jar-files']: - if j in enabled: - print("enabled " + j) - else: - print("disabled " + j) - - -def plugin_restore_status(): - lines = sys.stdin.readlines() - for line in lines: - line = line.strip() - if line.startswith("enabled "): - print("enable " + line.split(' ')[1]) - jar_status(line.split(' ')[1], True) - if line.startswith("disabled "): - jar_status(line.split(' ')[1], False) - check_compatibility() - - -def rudder_postupgrade(): - for plugin in DB["plugins"]: - script_dir = DB_DIRECTORY + "/" + plugin - run_script("postinst", script_dir, True) - -def plugin_disable_all(): - plugin_status(DB["plugins"].keys(), False) - - -def plugin_enable_all(): - plugin_status(DB["plugins"].keys(), True) - -def plugin_status(plugins, status): - for plugin in plugins: - if status: - print("Enabling " + plugin) - else: - print("Disabling " + plugin) - if plugin not in DB["plugins"]: - fail("Unknown plugin " + plugin) - metadata = DB["plugins"][plugin] - if 'jar-files' in metadata: - for j in metadata['jar-files']: - jar_status(j, status) - - -## MAIN -if __name__ == "__main__": - args = docopt.docopt(__doc__) - db_load() - jetty_needs_restart = False - - if args['install-file']: - install_file(args['']) - elif args['list']: - package_list() - elif args['remove']: - remove(args['']) - elif args['rudder-postupgrade']: - rudder_postupgrade() - elif args['check-compatibility']: - check_compatibility() - elif args['plugin']: - if args['save-status']: - plugin_save_status() - elif args['restore-status']: - plugin_restore_status() - elif args['enable']: - plugin_status(args[''], True) - elif args['enable-all']: - plugin_enable_all() - elif args['disable']: - plugin_status(args[''], False) - elif args['disable-all']: - plugin_disable_all() - - if jetty_needs_restart: - shell("service rudder-jetty restart", "Restarting jetty") diff --git a/rudder-server-relay/SOURCES/rudder-relay-apache b/rudder-server-relay/SOURCES/rudder-relay-apache deleted file mode 100644 index 360e7fca0..000000000 --- a/rudder-server-relay/SOURCES/rudder-relay-apache +++ /dev/null @@ -1,5 +0,0 @@ -# Apache modules -APACHE_MODULES="${APACHE_MODULES} dav dav_fs ssl version wsgi filter deflate" - -# Apache configuration flags -APACHE_SERVER_FLAGS="${APACHE_SERVER_FLAGS} SSL" diff --git a/rudder-server-relay/SOURCES/rudder-relay.cron b/rudder-server-relay/SOURCES/rudder-relay.cron deleted file mode 100644 index 9d7879476..000000000 --- a/rudder-server-relay/SOURCES/rudder-relay.cron +++ /dev/null @@ -1,5 +0,0 @@ -# Cron file for Rudder relay -# - -*/5 * * * * root /opt/rudder/share/relay-api/cleanup.sh >/dev/null - diff --git a/rudder-server-relay/SOURCES/rudder-relay.fc b/rudder-server-relay/SOURCES/rudder-relay.fc deleted file mode 100644 index fe47b7168..000000000 --- a/rudder-server-relay/SOURCES/rudder-relay.fc +++ /dev/null @@ -1,5 +0,0 @@ -/var/rudder/inventories/accepted-nodes-updates gen_context(system_u:object_r:httpd_sys_rw_content_t,s0) -/var/rudder/inventories/incoming gen_context(system_u:object_r:httpd_sys_rw_content_t,s0) -/var/log/rudder/apache2(/.*)? gen_context(system_u:object_r:httpd_log_t,s0) -/opt/rudder/etc/uuid.hive gen_context(system_u:object_r:httpd_sys_content_t,s0) - diff --git a/rudder-server-relay/SOURCES/rudder-relay.sudo b/rudder-server-relay/SOURCES/rudder-relay.sudo deleted file mode 100644 index 0392e33b7..000000000 --- a/rudder-server-relay/SOURCES/rudder-relay.sudo +++ /dev/null @@ -1,4 +0,0 @@ -# Allow the relay API to trigger remote runs -rudder ALL = NOPASSWD: /opt/rudder/bin/rudder remote run * -# Allow the relay API to trigger local runs -rudder ALL = NOPASSWD: /opt/rudder/bin/rudder agent run * diff --git a/rudder-server-relay/SOURCES/rudder-relay.te b/rudder-server-relay/SOURCES/rudder-relay.te deleted file mode 100644 index 6fbdc24d8..000000000 --- a/rudder-server-relay/SOURCES/rudder-relay.te +++ /dev/null @@ -1,12 +0,0 @@ -# Source file for rudder-webapp.pp -# # Generate rudder-webapp.pp by running: -# # make -f /usr/share/selinux/devel/Makefile - -module rudder-relay 1.0; - -require { - type httpd_log_t; - type httpd_sys_rw_content_t; - type httpd_sys_content_t; -} - diff --git a/rudder-server-relay/SOURCES/rudder-vhost.conf b/rudder-server-relay/SOURCES/rudder-vhost.conf deleted file mode 100644 index cb5311f70..000000000 --- a/rudder-server-relay/SOURCES/rudder-vhost.conf +++ /dev/null @@ -1,40 +0,0 @@ -# Set up a WSGI serving process common to ssl and non ssl vhost -WSGIDaemonProcess relay_api threads=5 user=rudder group=rudder -WSGISocketPrefix /var/run/wsgi - - - - ServerAdmin webmaster@localhost - - # Logs - LogLevel warn - CustomLog /var/log/rudder/apache2/access.log combined - ErrorLog /var/log/rudder/apache2/error.log - - # Include Rudder common vhost definitions - Include /opt/rudder/etc/rudder-apache-*-common.conf - - IncludeOptional /opt/rudder/etc/rudder-apache-*-nossl.conf - - - - - ServerAdmin webmaster@localhost - - # Logs - LogLevel warn - CustomLog /var/log/rudder/apache2/access.log combined - ErrorLog /var/log/rudder/apache2/error.log - - # SSL Engine Switch: - # Enable/Disable SSL for this virtual host. - SSLEngine on - - SSLCertificateFile /opt/rudder/etc/ssl/rudder.crt - SSLCertificateKeyFile /opt/rudder/etc/ssl/rudder.key - - # Include Rudder common vhost definitions - Include /opt/rudder/etc/rudder-apache-*-common.conf - - IncludeOptional /opt/rudder/etc/rudder-apache-*-ssl.conf - diff --git a/rudder-server-relay/SOURCES/ssl/ca.cert b/rudder-server-relay/SOURCES/ssl/ca.cert deleted file mode 100644 index e69de29bb..000000000