diff --git a/dry_run/.gitignore b/dry_run/.gitignore new file mode 100644 index 0000000..b52d0c0 --- /dev/null +++ b/dry_run/.gitignore @@ -0,0 +1,3 @@ +backup.ldif* +result.ldif* +sync.json* \ No newline at end of file diff --git a/dry_run/docker-compose.yml b/dry_run/docker-compose.yml new file mode 100644 index 0000000..e26bc53 --- /dev/null +++ b/dry_run/docker-compose.yml @@ -0,0 +1,22 @@ +--- + +services: + ldap: + image: ghcr.io/surfscz/sram-ldap:main + ports: + - 1389:1389 + environment: + LDAP_ROOT: "${BASEDN}" + LDAP_ADMIN_USERNAME: "admin" + LDAP_ADMIN_PASSWORD: "changethispassword" + LDAP_CONFIG_ADMIN_USERNAME: "admin" + LDAP_CONFIG_ADMIN_PASSWORD: "changethispassword" + LDAP_CONFIG_ADMIN_ENABLED: "yes" + LDAP_CUSTOM_SCHEMA_DIR: "/opt/ldap/schema" + LDAP_SKIP_DEFAULT_TREE: "yes" + LDAP_ENABLE_TLS: "no" + LDAP_ENABLE_SYNCPROV: "yes" + volumes: + - ./schema:/opt/ldap/schema + - ./ldif:/opt/ldap/ldif + - ./backup.ldif:/backup.ldif:ro \ No newline at end of file diff --git a/dry_run/dry-run.sh b/dry_run/dry-run.sh new file mode 100755 index 0000000..602274d --- /dev/null +++ b/dry_run/dry-run.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +set -e +shopt -s extglob # for the string postfix matching below + +cleanup() { + [ -n "$COMPOSE" ] && ${COMPOSE} rm --force --stop >/dev/null 2>&1 || true + [ -n "$SOCAT_PID" ] && kill "$SOCAT_PID" || true + [ -n "$TMPFILE" ] && rm -f "${TMPFILE}" || true +} +trap cleanup EXIT + +# check if data file are present +if [ ! -f "backup.ldif" ] || [ ! -f "sync.json" ]; then + echo "Data files backup.ldif and/or sync.json not found" + echo "Copy ldap backup (slapcat -n1 output) to backup.ldif" + echo "Copy SBS plsc sync output to sync.json" + exit 1 +fi + +GREEN="\033[0;32m" +NORMAL="\033[0m" + +# check if we're using a remote docker host +# in that case, we need to forward the local port 1389 to the real docker host +# because all scripts depend on the ldap being available locally +docker_host=$(docker context inspect -f '{{ .Endpoints.docker.Host }}') +docker_proto=${docker_host:0:6} +if [ "$docker_proto" == "tcp://" ]; then + # remove protocol + HOST=${docker_host:6} + # remove port number + HOST=${HOST%:+([[:digit:]])?(/)} + + echo "Using remote docker host $HOST ($docker_host)" + socat "TCP4-LISTEN:1389,fork,reuseaddr" "TCP4:${HOST}:1389" 2>/dev/null & + SOCAT_PID=$! +fi + + +# find basedn +BASEDN=$( awk '/^dn: / { print $2; exit }' backup.ldif ) +export BASEDN +echo "Found basedn '$BASEDN'" + +COMPOSE_FILE="docker-compose.yml" +COMPOSE="docker compose --file ${COMPOSE_FILE}" + +echo -n "Starting containers..." +${COMPOSE} rm --force --stop >/dev/null 2>&1 || true +${COMPOSE} up --detach >/dev/null 2>&1 +echo + +echo -n "Waiting for ldap to start" +while sleep 0.2 +do + echo -n "." + if docker compose logs | grep -q '\*\* Starting slapd \*\*' + then + echo " Up!" + break + fi +done + +echo "Configuring LDAP" +${COMPOSE} exec ldap ldapmodify -H ldap://localhost:1389/ -D cn=admin,cn=config -w changethispassword -f /opt/ldap/ldif/config_1.ldif > /dev/null 2>&1 +${COMPOSE} exec ldap ldapadd -H ldap://localhost:1389/ -D cn=admin,cn=config -w changethispassword -f /opt/ldap/ldif/config_2.ldif > /dev/null 2>&1 + +echo "Loading data" +${COMPOSE} exec ldap slapadd -F /opt/bitnami/openldap/etc/slapd.d/ -n 2 -l /backup.ldif > /dev/null 2>&1 + +# generate plsc config +echo "Generating plsc config" +TMPFILE=$(mktemp -t plsc_XXXXXX.yml) +cat < "${TMPFILE}" + --- + ldap: + src: + uri: "ldap://localhost:1389/" + basedn: "${BASEDN}" + binddn: "cn=admin,${BASEDN}" + passwd: "changethispassword" + sizelimit: 5 + dst: + uri: "ldap://localhost:1389/" + basedn: "${BASEDN}" + binddn: "cn=admin,${BASEDN}" + passwd: "changethispassword" + sizelimit: 5 + sbs: + src: + host: "test" + sync: "dry_run/sync.json" + pwd: '{CRYPT}!' + uid: 1000 + gid: 1000 +EOF + +# install venv +if ! test -d '../venv' +then + echo -n "Installing venv..." + python3 -mvenv ../venv + ../venv/bin/pip install -q --upgrade pip wheel setuptools + ../venv/bin/pip install -q -r ../requirements.txt + echo +fi + + +#export LOGLEVEL=DEBUG +echo "Running plsc" +( + cd .. + export PATH="$(pwd)/venv/bin:${PATH}" + ./run.sh "${TMPFILE}" +) + +echo Dumping result +docker-compose -f docker-compose.yml exec -ti ldap slapcat -F /opt/bitnami/openldap/etc/slapd.d/ -o ldif-wrap=no -n2 > result.ldif 2>/dev/null + +echo Comparing result +../venv/bin/python ./ldifparser.py < backup.ldif > backup.ldif.parsed +../venv/bin/python ./ldifparser.py < result.ldif > result.ldif.parsed +diff --unified --text --color=always backup.ldif.parsed result.ldif.parsed && echo -e "${GREEN}No changes detected!${NORMAAL}" + +exit 0 \ No newline at end of file diff --git a/dry_run/ldif/KEEP b/dry_run/ldif/KEEP new file mode 100644 index 0000000..e69de29 diff --git a/dry_run/ldif/config_1.ldif b/dry_run/ldif/config_1.ldif new file mode 100644 index 0000000..6404f19 --- /dev/null +++ b/dry_run/ldif/config_1.ldif @@ -0,0 +1,32 @@ +dn: cn=config +changetype: Modify +add: olcAttributeOptions +olcAttributeOptions: time- + +dn: cn=module{1},cn=config +changetype: Modify +add: olcModuleLoad +olcModuleLoad: {1}dynlist.so + +dn: olcDatabase={2}mdb,cn=config +changetype: Modify +replace: olcDbIndex +olcDbIndex: objectClass eq,pres +olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub +olcDbIndex: entryUUID eq +olcDbIndex: o eq +olcDbIndex: dc eq +olcDbIndex: entryCSN eq + +replace: olcDbMaxSize +olcDbMaxSize: 1073741824 + +replace: olcAccess +olcAccess: {0}to dn.regex="(([^,]+),dc=services,dc=vnet)$" by dn.exact="cn=adm + in,dc=services,dc=vnet" write by dn.exact=gidNumber=0+uidNumber=0,cn=peercred + ,cn=external,cn=auth write by dn.exact,expand="cn=admin,$1" read by * break +olcAccess: {1}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external + ,cn=auth manage by dn.regex="cn=[^,]+,dc=services,dc=vnet" read by dn.exact= + gidNumber=1000+uidNumber=1000,cn=peercred,cn=external,cn=auth manage by * br + eak +olcAccess: {2}to attrs=userPassword by self write by anonymous auth by * break diff --git a/dry_run/ldif/config_2.ldif b/dry_run/ldif/config_2.ldif new file mode 100644 index 0000000..9816103 --- /dev/null +++ b/dry_run/ldif/config_2.ldif @@ -0,0 +1,5 @@ +dn: olcOverlay={1}dynlist,olcDatabase={2}mdb,cn=config +objectClass: olcOverlayConfig +objectClass: olcDynListConfig +olcOverlay: {1}dynlist +olcDynListAttrSet: {0}voPerson labeledURI member+memberOf@groupOfMembers diff --git a/dry_run/ldifparser.py b/dry_run/ldifparser.py new file mode 100644 index 0000000..35fd383 --- /dev/null +++ b/dry_run/ldifparser.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +import sys +import ldif +from collections import OrderedDict + + +def kcmp(item): + (key, v) = item + parts = key.split(',')[::-1] + new_key = ','.join(parts) + return (new_key, v) + + +def freeze(o): + if isinstance(o, dict): + return OrderedDict({k: freeze(v) for k, v in sorted(o.items(), key=kcmp)}.items()) + if isinstance(o, list): + return sorted([freeze(v) for v in o]) + return o.decode('utf-8') + + +def my_print(o, depth): + if isinstance(o, OrderedDict): + for k, v in o.items(): + my_print(k, depth) + my_print(v, depth + 2) + elif isinstance(o, list): + for v in o: + my_print(v, depth) + else: + print(f"{' ' * depth}{o}") + + +ldifparser = ldif.LDIFRecordList(sys.stdin) +ldifparser.parse() + +data = {k: v for k, v in ldifparser.all_records} +f = freeze(data) + +# print(json.dumps(f, indent=2)) +my_print(f, 0) diff --git a/dry_run/schema/eduMember.ldif b/dry_run/schema/eduMember.ldif new file mode 100644 index 0000000..42894d5 --- /dev/null +++ b/dry_run/schema/eduMember.ldif @@ -0,0 +1,27 @@ +dn: cn=eduMember,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: eduMember +# Internet X.500 Schema for Ldappc +# Includes the eduMember ObjectClass schema +# +# +# An auxiliary object class, "eduMember," is a convenient container +# for an extensible set of attributes concerning group memberships. +# At this time, the only attributes specified as belonging to the +# object class are "isMemberOf" and "hasMember." +# +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.5.1.1 + NAME 'isMemberOf' + DESC 'identifiers for groups to which containing entity belongs' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.5.1.2 + NAME 'hasMember' + DESC 'identifiers for entities that are members of the group' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcObjectClasses: ( 1.3.6.1.4.1.5923.1.5.2.1 + NAME 'eduMember' + AUXILIARY + MAY ( isMemberOf $ hasMember ) + ) diff --git a/dry_run/schema/eduPerson.ldif b/dry_run/schema/eduPerson.ldif new file mode 100644 index 0000000..e4f2c96 --- /dev/null +++ b/dry_run/schema/eduPerson.ldif @@ -0,0 +1,83 @@ +dn: cn=eduperson,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: eduperson +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.1 + NAME 'eduPersonAffiliation' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.7 + NAME 'eduPersonEntitlement' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.2 + NAME 'eduPersonNickName' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.3 + NAME 'eduPersonOrgDN' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.4 + NAME 'eduPersonOrgUnitDN' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.5 + NAME 'eduPersonPrimaryAffiliation' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.8 + NAME 'eduPersonPrimaryOrgUnitDN' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.6 + NAME 'eduPersonPrincipalName' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.12 + NAME 'eduPersonPrincipalNamePrior' + DESC 'eduPersonPrincipalNamePrior per Internet2' + EQUALITY caseIgnoreMatch + SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.9 + NAME 'eduPersonScopedAffiliation' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.10 + NAME 'eduPersonTargetedID' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.11 + NAME 'eduPersonAssurance' + DESC 'eduPerson per Internet2 and EDUCAUSE' + EQUALITY caseExactMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.13 + NAME 'eduPersonUniqueId' + DESC 'eduPersonUniqueId per Internet2' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5923.1.1.1.16 + NAME 'eduPersonOrcid' + DESC 'ORCID researcher identifiers belonging to the principal' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcObjectClasses: ( 1.3.6.1.4.1.5923.1.1.2 + NAME 'eduPerson' + AUXILIARY + MAY ( + eduPersonAffiliation $ eduPersonNickname $ eduPersonOrgDN $ + eduPersonOrgUnitDN $ eduPersonPrimaryAffiliation $ + eduPersonPrincipalName $ eduPersonEntitlement $ eduPersonPrimaryOrgUnitDN $ + eduPersonScopedAffiliation $ eduPersonTargetedID $ eduPersonAssurance $ + eduPersonPrincipalNamePrior $ eduPersonUniqueId $ eduPersonOrcid ) + ) diff --git a/dry_run/schema/groupOfMembers.ldif b/dry_run/schema/groupOfMembers.ldif new file mode 100644 index 0000000..aa10094 --- /dev/null +++ b/dry_run/schema/groupOfMembers.ldif @@ -0,0 +1,19 @@ +# Internet X.500 Schema for Ldappc +# Includes the groupOfMembers ObjectClass schema +# +# Taken from RFC2307bis draft 2 +# https://tools.ietf.org/html/draft-howard-rfc2307bis-02 +# +# An structural object class, "groupOfMembers" is a convenient container +# for an extensible set of attributes concerning group memberships. +# +dn: cn=groupOfMembers,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: groupOfMembers +olcObjectClasses: ( 1.3.6.1.1.1.2.18 SUP top STRUCTURAL + NAME 'groupOfMembers' + DESC 'A group with members (DNs)' + MUST cn + MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ + description $ member ) + ) diff --git a/dry_run/schema/ldapPublicKey.ldif b/dry_run/schema/ldapPublicKey.ldif new file mode 100644 index 0000000..8968b6e --- /dev/null +++ b/dry_run/schema/ldapPublicKey.ldif @@ -0,0 +1,21 @@ +dn: cn=openssh-lpk-openldap,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: openssh-lpk-openldap +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey +# useful with PKA-LDAP also +# +# Author: Eric AUGE +# +# Based on the proposal of : Mark Ruijter +# +# octetString SYNTAX +olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' + DESC 'MANDATORY: OpenSSH Public key' + EQUALITY octetStringMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +# printableString SYNTAX yes|no +olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY + DESC 'MANDATORY: OpenSSH LPK olcObjectClasses:' + MUST ( sshPublicKey $ uid ) + ) diff --git a/dry_run/schema/sczGroup.ldif b/dry_run/schema/sczGroup.ldif new file mode 100644 index 0000000..d1b5cb3 --- /dev/null +++ b/dry_run/schema/sczGroup.ldif @@ -0,0 +1,23 @@ +# Internet X.500 Schema for Ldappc +# Includes the sczGroup ObjectClass schema +# +# An auxiliary object class, "sczGroup," is a convenient container +# for an extensible set of attributes concerning group memberships. +# At this time, the only attribute specified as belonging to the +# object class is "sczMember." +# +# It is specifically configured to support the memberOf overlay. +# +dn: cn=sczGroup,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: sczGroup +olcAttributeTypes: ( 1.3.6.1.4.1.1076.20.40.50.1.1 + NAME 'sczMember' + DESC 'DN identifiers for entities that are members of the group' + EQUALITY distinguishedNameMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcObjectClasses: ( 1.3.6.1.4.1.1076.20.40.50.1 + NAME 'sczGroup' + AUXILIARY + MAY ( sczMember ) + ) diff --git a/dry_run/schema/voPerson.ldif b/dry_run/schema/voPerson.ldif new file mode 100644 index 0000000..bdce11e --- /dev/null +++ b/dry_run/schema/voPerson.ldif @@ -0,0 +1,44 @@ +dn: cn=voperson,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: voperson +olcAttributeTypes: {0}( 1.3.6.1.4.1.34998.3.3.1.1 NAME 'voPersonApplicationUID + ' DESC 'voPerson Application-Specific User Identifier' EQUALITY caseIgnoreMat + ch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' ) +olcAttributeTypes: {1}( 1.3.6.1.4.1.34998.3.3.1.2 NAME 'voPersonAuthorName' DE + SC 'voPerson Author Name' EQUALITY caseIgnoreMatch SYNTAX '1.3.6.1.4.1.1466.1 + 15.121.1.15' ) +olcAttributeTypes: {2}( 1.3.6.1.4.1.34998.3.3.1.3 NAME 'voPersonCertificateDN' + DESC 'voPerson Certificate Distinguished Name' EQUALITY distinguishedNameMat + ch SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' ) +olcAttributeTypes: {3}( 1.3.6.1.4.1.34998.3.3.1.4 NAME 'voPersonCertificateIss + uerDN' DESC 'voPerson Certificate Issuer DN' EQUALITY distinguishedNameMatch + SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' ) +olcAttributeTypes: {4}( 1.3.6.1.4.1.34998.3.3.1.5 NAME 'voPersonExternalID' DE + SC 'voPerson Scoped External Identifier' EQUALITY caseIgnoreMatch SYNTAX '1.3 + .6.1.4.1.1466.115.121.1.15' ) +olcAttributeTypes: {5}( 1.3.6.1.4.1.34998.3.3.1.6 NAME 'voPersonID' DESC 'voPe + rson Unique Identifier' EQUALITY caseIgnoreMatch SYNTAX '1.3.6.1.4.1.1466.115 + .121.1.15' ) +olcAttributeTypes: {6}( 1.3.6.1.4.1.34998.3.3.1.7 NAME 'voPersonPolicyAgreemen + t' DESC 'voPerson Policy Agreement Indicator' EQUALITY caseIgnoreMatch SYNTAX + '1.3.6.1.4.1.1466.115.121.1.15' ) +olcAttributeTypes: {7}( 1.3.6.1.4.1.34998.3.3.1.8 NAME 'voPersonSoRID' DESC 'v + oPerson External Identifier' EQUALITY caseIgnoreMatch SYNTAX '1.3.6.1.4.1.146 + 6.115.121.1.15' ) +olcAttributeTypes: {8}( 1.3.6.1.4.1.34998.3.3.1.9 NAME 'voPersonStatus' DESC ' + voPerson Status' EQUALITY caseIgnoreMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1. + 15' ) +olcAttributeTypes: {9}( 1.3.6.1.4.1.34998.3.3.1.10 NAME 'voPersonAffiliation' + DESC 'voPerson Affiliation Within Local Scope' EQUALITY caseIgnoreMatch SYNTA + X '1.3.6.1.4.1.1466.115.121.1.15' ) +olcAttributeTypes: {10}( 1.3.6.1.4.1.34998.3.3.1.11 NAME 'voPersonExternalAffi + liation' DESC 'voPerson Scoped External Affiliation' EQUALITY caseIgnoreMatch + SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' ) +olcAttributeTypes: {11}( 1.3.6.1.4.1.34998.3.3.1.12 NAME 'voPersonScopedAffili + ation' DESC 'voPerson Affiliation With Explicit Local Scope' EQUALITY caseIgn + oreMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' ) +olcObjectClasses: {0}( 1.3.6.1.4.1.34998.3.3.1 NAME 'voPerson' AUXILIARY MAY ( + voPersonAffiliation $ voPersonApplicationUID $ voPersonAuthorName $ voPerson + CertificateDN $ voPersonCertificateIssuerDN $ voPersonExternalAffiliation $ v + oPersonExternalID $ voPersonID $ voPersonPolicyAgreement $ voPersonScopedAffi + liation $ voPersonSoRID $ voPersonStatus ) ) diff --git a/dump_sbs.py b/dump_sbs.py new file mode 100755 index 0000000..3b9506a --- /dev/null +++ b/dump_sbs.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +import sys +import yaml +import json + +from sbs import SBS + + +def main(): + if len(sys.argv) < 2: + sys.exit(sys.argv[0] + " ") + + with open(sys.argv[1]) as f: + config = yaml.safe_load(f) + + src = SBS(config['sbs']['src']) + sync = src.api("api/plsc/sync") + + print(json.dumps(sync, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/plsc.yml.example b/plsc.yml.example index 8b73dd8..f37c3a8 100644 --- a/plsc.yml.example +++ b/plsc.yml.example @@ -15,6 +15,8 @@ ldap: sbs: src: host: https://sbs.example.net + # host: test + # sync: sync.json user: sysread passwd: changethispassword verify_ssl: True diff --git a/run.sh b/run.sh index 2e5d357..d4157dd 100755 --- a/run.sh +++ b/run.sh @@ -13,4 +13,4 @@ elif [ ! -f "$1" ]; then fi /usr/bin/env python plsc_ordered.py "$1" -/usr/bin/env python plsc_flat.py "$1" +/usr/bin/env python plsc_flat.py "$1" \ No newline at end of file diff --git a/sbs.py b/sbs.py index 67b6e0b..0f2230f 100644 --- a/sbs.py +++ b/sbs.py @@ -37,6 +37,9 @@ def __init__(self, config): self.retry = config.get('retry', 3) self.recording_requested = config.get('recorder', False) + if self.host == 'test': + self.sync = config['sync'] + if config.get("ipv4_only", False): import urllib3.util.connection as urllib3_connection @@ -69,6 +72,9 @@ class SBSNoContentException(Exception): logger.debug(f"API: {request}...") + if self.host == 'test' and request == 'api/plsc/sync': + return json.loads(open(self.sync, 'r').read()) + # retry the entire process a few times` for i in range(0, self.retry): try: