misc
This commit is contained in:
commit
48641cd9c1
|
@ -0,0 +1,4 @@
|
|||
__pycache__
|
||||
*.pyc
|
||||
*~
|
||||
*.swp
|
|
@ -0,0 +1 @@
|
|||
*.retry
|
|
@ -0,0 +1,6 @@
|
|||
[defaults]
|
||||
|
||||
inventory_plugins = library
|
||||
|
||||
[inventory]
|
||||
enable_plugins = inventory
|
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/python3
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||
|
||||
p = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.path.insert(0, p)
|
||||
from data import serverlist
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
NAME = 'entrouvert' # used internally by Ansible, it should match the file name but not required
|
||||
|
||||
def verify_file(self, path):
|
||||
return True
|
||||
|
||||
def parse(self, inventory, loader, path, cache=False):
|
||||
|
||||
#self.loader = loader
|
||||
#self.inventory = inventory
|
||||
#self.templar = Templar(loader=loader)
|
||||
|
||||
# call base method to ensure properties are available for use with other helper methods
|
||||
super(InventoryModule, self).parse(inventory, loader, path, cache)
|
||||
|
||||
|
||||
"""
|
||||
# this method will parse 'common format' inventory sources and
|
||||
# update any options declared in DOCUMENTATION as needed
|
||||
config = self._read_config_data(path)
|
||||
|
||||
# if NOT using _read_config_data you should call set_options directly,
|
||||
# to process any defined configuration for this plugin,
|
||||
# if you don't define any options you can skip
|
||||
#self.set_options()
|
||||
|
||||
# example consuming options from inventory source
|
||||
mysession = apilib.session(user=self.get_option('api_user'),
|
||||
password=self.get_option('api_pass'),
|
||||
server=self.get_option('api_server')
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
"""
|
||||
# make requests to get data to feed into inventory
|
||||
mydata = mysession.getitall()
|
||||
|
||||
#parse data and create inventory objects:
|
||||
for colo in mydata:
|
||||
for server in mydata[colo]['servers']:
|
||||
self.inventory.add_host(server['name'])
|
||||
self.inventory.set_variable(server['name'], 'ansible_host', server['external_ip'])
|
||||
"""
|
||||
|
||||
for s in serverlist:
|
||||
self.inventory.add_host(s)
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
- hosts: node2.dev.saas.entrouvert.org
|
||||
tasks:
|
||||
- assert:
|
||||
that:
|
||||
- "inventory_hostname == ansible_fqdn"
|
||||
- "ansible_eno1.macaddress == 'ac:1f:6b:44:55:84'"
|
||||
- "ansible_default_ipv4 == 'ansible_default_ipv4'"
|
|
@ -0,0 +1 @@
|
|||
output
|
|
@ -0,0 +1,43 @@
|
|||
.PHONY: clean all collect
|
||||
|
||||
collect: clean output output/dev.saas.entrouvert.org output/test.saas.entrouvert.org output/prod.saas.entrouvert.org
|
||||
echo 'This files where generated by entrouvert-remotes (maybe triggered by eotasks)' > output/README
|
||||
echo done
|
||||
|
||||
output/dev.saas.entrouvert.org:
|
||||
mkdir $@
|
||||
scp collect_connections.py authentic.node1.dev.saas.entrouvert.org:/tmp/
|
||||
scp collect_connections.py passerelle.node1.dev.saas.entrouvert.org:/tmp/
|
||||
ssh authentic.node1.dev.saas.entrouvert.org sudo -u authentic-multitenant authentic2-multitenant-manage runscript /tmp/collect_connections.py > $@/authentic
|
||||
ssh passerelle.node1.dev.saas.entrouvert.org sudo -u passerelle passerelle-manage runscript /tmp/collect_connections.py > $@/passerelle
|
||||
# TODO: proper wcs adresses collection
|
||||
# scp collect_connections.py wcs.node1.dev.saas.entrouvert.org:/tmp/
|
||||
# ssh wcs.node1.dev.saas.entrouvert.org sudo -u wcs wcs-manage runscript /tmp/collect_connections.py > output/dev_entries/wcs.node1.dev.saas.entrouvert.org
|
||||
|
||||
output/test.saas.entrouvert.org:
|
||||
mkdir $@
|
||||
scp collect_connections.py authentic.node1.test.saas.entrouvert.org:/tmp/
|
||||
scp collect_connections.py passerelle.node1.test.saas.entrouvert.org:/tmp/
|
||||
ssh authentic.node1.test.saas.entrouvert.org sudo -u authentic-multitenant authentic2-multitenant-manage runscript /tmp/collect_connections.py > $@/authentic
|
||||
ssh passerelle.node1.test.saas.entrouvert.org sudo -u passerelle passerelle-manage runscript /tmp/collect_connections.py > $@/passerelle
|
||||
# TODO: proper wcs adresses collection
|
||||
|
||||
output/prod.saas.entrouvert.org:
|
||||
mkdir $@
|
||||
scp collect_connections.py authentic.rbx.prod.entrouvert.org:/tmp/
|
||||
scp collect_connections.py passerelle.rbx.prod.entrouvert.org:/tmp/
|
||||
ssh authentic.rbx.prod.entrouvert.org sudo -u authentic-multitenant authentic2-multitenant-manage runscript /tmp/collect_connections.py > $@/authentic
|
||||
ssh passerelle.rbx.prod.entrouvert.org sudo -u passerelle passerelle-manage runscript /tmp/collect_connections.py > $@/passerelle
|
||||
|
||||
output/chicon.entrouvert.org:
|
||||
mkdir $@
|
||||
scp collect_connections.py authentic.entrouvert.org:/tmp/
|
||||
scp collect_connections.py passerelle.entrouvert.org:/tmp/
|
||||
ssh authentic.entrouvert.org sudo -u authentic-multitenant authentic2-multitenant-manage runscript /tmp/collect_connections.py > $@/authentic
|
||||
ssh passerelle.entrouvert.org sudo -u passerelle passerelle-manage runscript /tmp/collect_connections.py > $@/passerelle
|
||||
|
||||
output:
|
||||
mkdir output
|
||||
|
||||
clean:
|
||||
-test -d output && rm -r output
|
|
@ -0,0 +1,100 @@
|
|||
# hobo - portal to configure and deploy applications
|
||||
# Copyright (C) 2016 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import json
|
||||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
from hobo.multitenant.middleware import TenantMiddleware
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def handle(self, verbosity=0, *args, **options):
|
||||
entries = {}
|
||||
for tenant in TenantMiddleware.get_tenants():
|
||||
if verbosity > 0:
|
||||
print(u'* Running command on tenant %s' % tenant.domain_url)
|
||||
connection.set_tenant(tenant)
|
||||
key = tenant.domain_url
|
||||
entries[key] = []
|
||||
for entry in self.tenant_entries():
|
||||
entries[key].append(entry)
|
||||
|
||||
# hack (see TODO further on)
|
||||
if os.path.isfile('/usr/bin/passerelle-manage'):
|
||||
entries['wcs'] = []
|
||||
for entry in self.wcs_remotes():
|
||||
entries['wcs'].append(entry)
|
||||
|
||||
print(json.dumps(entries))
|
||||
|
||||
def tenant_entries(self, *args, **options):
|
||||
entries = []
|
||||
if os.path.isfile('/usr/bin/passerelle-manage'):
|
||||
entries.extend(self.passerelle_remotes())
|
||||
## TODO: proper wcs entries collection
|
||||
# if os.path.isfile('/usr/bin/wcs-manage'):
|
||||
# entries.extend(self.wcs_remotes())
|
||||
if os.path.isfile('/usr/bin/authentic2-multitenant-manage'):
|
||||
entries.extend(self.authentic_remotes())
|
||||
return entries
|
||||
|
||||
def authentic_remotes(self):
|
||||
for s in settings.LDAP_AUTH_SETTINGS:
|
||||
if isinstance(s['url'], list):
|
||||
for entry in s['url']:
|
||||
yield entry
|
||||
else:
|
||||
yield(s['url'])
|
||||
|
||||
def passerelle_remotes(self):
|
||||
from passerelle.views import get_all_apps
|
||||
|
||||
for app in get_all_apps():
|
||||
for connector in app.objects.all():
|
||||
for attr in connector.__dict__.keys():
|
||||
if attr.endswith('url'):
|
||||
url = getattr(connector, attr, None)
|
||||
if url:
|
||||
yield(url)
|
||||
|
||||
def wcs_remotes(self):
|
||||
"""
|
||||
os.system('grep --color https:// */{formdefs,workflows,datasources,wscalls}/* | grep -v href= | grep -v src= | grep -o "https://.*" | sort | uniq')
|
||||
"""
|
||||
|
||||
ls = '''https://api.wavebricks.com/#/register?firstname=[form_var_firstname]&lastname=[form_var_lastname]&email=[form_var_courriel]&type_utilisateur=@IF&referrer=EMS2017
|
||||
https://sp01.vincennes.fr/webhook-comptecitoyen/
|
||||
https://bacasable.atreal.fr/~demowsdia/openads/services/rest_entry.php/dia/
|
||||
https://secure2.grandnancy.eu/grcnancywebservices/symfony/web/app_dev.php/eo/test
|
||||
https://si.metzmetropole.fr/index.php
|
||||
https://si.metzmetropole.fr/index.php?appid=252&q=gare
|
||||
https://si-ws-dev.metzmetropole.fr/adp/putAnomaliePublik.php
|
||||
https://si-ws.metzmetropole.fr/adp/____putAnomaliePublik.php
|
||||
https://si-ws.metzmetropole.fr/adp/putAnomaliePublik.php
|
||||
https://si-ws.metzmetropole.fr/sig/getquartierbyadress.php?q=3%20rue%20des%20eglantiers
|
||||
https://srv-geoserver.mairie-metz.fr/public/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=public:fdp_voi_nume&maxFeatures=50&outputFormat=application/json
|
||||
https://srv-siapps.mairie-metz.fr/index.php'''
|
||||
|
||||
for l in ls.splitlines():
|
||||
yield l.strip()
|
||||
|
||||
|
||||
command = Command()
|
||||
command.handle()
|
|
@ -0,0 +1,101 @@
|
|||
#!/usr/bin/python2
|
||||
# hobo - portal to configure and deploy applications
|
||||
# Copyright (C) 2016 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import errno
|
||||
import json
|
||||
import socket
|
||||
import sys
|
||||
from urlparse import urlparse
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def ad_argument(self, parser):
|
||||
parser.add_argument('json_filename', type=str)
|
||||
|
||||
def handle(self, json_filename, verbosity=0, *args, **kwargs):
|
||||
cache = {}
|
||||
if json_filename == '-':
|
||||
entries = json.load(sys.stdin)
|
||||
else:
|
||||
entries = json.load(open(json_filename))
|
||||
for tenant, addresses in entries.iteritems():
|
||||
for entry in addresses:
|
||||
if entry in cache.keys():
|
||||
# return cache.get(entry)
|
||||
continue
|
||||
if verbosity > 0:
|
||||
print("testing %s %s" % (tenant, entry))
|
||||
host, port, scheme = self.parse_entry(entry)
|
||||
rs = self.netcat(host, port)
|
||||
cache[entry] = rs
|
||||
if not rs:
|
||||
print("Failed: %s (%s:%s %s) %s" % (tenant, host, port, scheme, rs))
|
||||
|
||||
def netcat(self, host, port, content=''):
|
||||
def connect(host, port, content):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(3)
|
||||
s.connect((host, int(port)))
|
||||
s.sendall(content.encode())
|
||||
s.shutdown(socket.SHUT_WR)
|
||||
while True:
|
||||
try:
|
||||
data = s.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
# print(repr(data))
|
||||
except socket.error as e:
|
||||
if e.errno != errno.ECONNRESET:
|
||||
raise
|
||||
s.close()
|
||||
try:
|
||||
connect(host, port, content)
|
||||
return True
|
||||
# python3
|
||||
# except socket.ConnectionResetError:
|
||||
# return True
|
||||
# except socket.ConnectionRefusedError:
|
||||
# return False
|
||||
except socket.timeout:
|
||||
return False
|
||||
except socket.gaierror:
|
||||
return False
|
||||
except socket.error:
|
||||
return False
|
||||
|
||||
def parse_entry(self, entry):
|
||||
parsed = urlparse(entry)
|
||||
try:
|
||||
host, port = parsed.netloc.split(':')
|
||||
port = int(port)
|
||||
except ValueError:
|
||||
host, port = parsed.netloc, 443
|
||||
if parsed.scheme == 'ldap':
|
||||
port = 389
|
||||
if parsed.scheme == 'ldaps':
|
||||
port = 636
|
||||
if parsed.scheme == 'http':
|
||||
port = 80
|
||||
if '@' in host:
|
||||
host = host.split('@')[-1]
|
||||
return host, port, parsed.scheme
|
||||
|
||||
|
||||
command = Command()
|
||||
command.handle(sys.argv[1])
|
|
@ -0,0 +1,2 @@
|
|||
ovh.conf
|
||||
output
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
import ovh
|
||||
|
||||
# create a client using configuration
|
||||
client = ovh.Client()
|
||||
|
||||
# Request RO, /me API access
|
||||
ck = client.new_consumer_key_request()
|
||||
ck.add_rules(ovh.API_READ_ONLY, "/me/*")
|
||||
ck.add_rules(ovh.API_READ_ONLY, "/dedicated/*")
|
||||
|
||||
# Request token
|
||||
validation = ck.request()
|
||||
print(validation)
|
||||
print("Please visit %s to authenticate" % validation['validationUrl'])
|
||||
input("and press Enter to continue...")
|
||||
|
||||
# Print nice welcome message
|
||||
print("Welcome", client.get('/me')['firstname'])
|
||||
print("Btw, your 'consumerKey' is '%s'" % validation['consumerKey'])
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import ovh
|
||||
import socket
|
||||
import yaml
|
||||
|
||||
client = ovh.Client()
|
||||
|
||||
ovh_servers = {}
|
||||
servers = {k: {} for k in client.get('/dedicated/server')}
|
||||
for s, _ in servers.items():
|
||||
name, _, addresslist = socket.gethostbyaddr(socket.gethostbyname(s))
|
||||
servers[s]['name'] = name
|
||||
servers[s]['ovh_name'] = s
|
||||
servers[s]['address'] = addresslist[0]
|
||||
servers[s]['base'] = client.get('/dedicated/server/%s' % s)
|
||||
servers[s]['ips'] = client.get('/dedicated/server/%s/ips' % s)
|
||||
servers[s]['options'] = client.get('/dedicated/server/%s/option' % s)
|
||||
servers[s]['hardware'] = client.get('/dedicated/server/%s/specifications/hardware' % s)
|
||||
servers[s]['ip'] = client.get('/dedicated/server/%s/specifications/ip' % s)
|
||||
servers[s]['network'] = client.get('/dedicated/server/%s/specifications/network' % s)
|
||||
servers[s]['interfaces'] = {i: {} for i in client.get('/dedicated/server/%s/networkInterfaceController' % s)}
|
||||
for m, _ in servers[s]['interfaces'].items():
|
||||
servers[s]['interfaces'][m]['type'] = client.get('/dedicated/server/%s/networkInterfaceController/%s' % (s, m))
|
||||
if servers[s]['interfaces'][m]['type']['linkType'] == 'public':
|
||||
if 'macaddress' in servers[s].keys():
|
||||
print('ERROR: %s has multiple public network interfaces' % s)
|
||||
servers[s]['macaddress'] = m
|
||||
|
||||
if servers[s]['name'] != servers[s]['base']['reverse'] or '%s.' % servers[s]['name'] != servers[s]['base']['reverse']:
|
||||
print('ERROR: %s reverse DNS is wrong' % s)
|
||||
if servers[s]['address'] != servers[s]['base']['ip'] or servers[s]['address'] != servers[s]['network']['routing']['ipv4']['ip']:
|
||||
print('ERROR: %s ip address is wrong' % s)
|
||||
|
||||
# reindex according to entrouvert key
|
||||
ovh_servers[servers[s]['name']] = servers[s]
|
||||
|
||||
print(yaml.dump(ovh_servers))
|
|
@ -0,0 +1,78 @@
|
|||
[DEFAULT]
|
||||
update = git pull --rebase
|
||||
|
||||
[auquotidien]
|
||||
checkout = git@git.entrouvert.org:auquotidien.git
|
||||
|
||||
[authentic]
|
||||
checkout = git@git.entrouvert.org:authentic.git
|
||||
|
||||
[authentic2-auth-fc]
|
||||
checkout = git clone git@git.entrouvert.org:authentic2-auth-fc.git
|
||||
|
||||
[authentic2-auth-fedict]
|
||||
checkout = git clone git@git.entrouvert.org:authentic2-auth-fedict.git
|
||||
|
||||
[authentic2-auth-kerberos]
|
||||
checkout = git clone git@git.entrouvert.org:authentic2-auth-kerberos.git
|
||||
|
||||
[authentic2-auth-msp]
|
||||
checkout = git clone git@git.entrouvert.org:authentic2-auth-msp.git
|
||||
|
||||
[authentic2-auth-saml2]
|
||||
checkout = git clone git@git.entrouvert.org:authentic2-auth-saml2.git
|
||||
|
||||
[bidon]
|
||||
checkout = git@git.entrouvert.org:bidon.git
|
||||
|
||||
[bijoe]
|
||||
checkout = git@git.entrouvert.org:bijoe.git
|
||||
|
||||
[chrono]
|
||||
checkout = git@git.entrouvert.org:chrono.git
|
||||
|
||||
[combo]
|
||||
checkout = git@git.entrouvert.org:combo.git
|
||||
|
||||
[corbo]
|
||||
checkout = git@git.entrouvert.org:corbo.git
|
||||
|
||||
[django-mellon]
|
||||
checkout = git@git.entrouvert.org:django-mellon.git
|
||||
|
||||
[django-tenant-schemas]
|
||||
checkout = git@git.entrouvert.org:django-tenant-schemas.git
|
||||
|
||||
[fargo]
|
||||
checkout = git@git.entrouvert.org:fargo.git
|
||||
|
||||
[gadjo]
|
||||
checkout = git@git.entrouvert.org:gadjo.git
|
||||
|
||||
[hobo]
|
||||
checkout = git@git.entrouvert.org:hobo.git
|
||||
|
||||
[lasso]
|
||||
checkout = git@git.entrouvert.org:lasso.git
|
||||
|
||||
[lingo]
|
||||
checkout = git@git.entrouvert.org:lingo.git
|
||||
|
||||
[mandayejs]
|
||||
checkout = git@git.entrouvert.org:mandayejs.git
|
||||
|
||||
[passerelle]
|
||||
checkout = git@git.entrouvert.org:passerelle.git
|
||||
|
||||
[publik-base-theme]
|
||||
checkout = git@git.entrouvert.org:publik-base-theme.git
|
||||
|
||||
[wcs]
|
||||
checkout = git@git.entrouvert.org:wcs.git
|
||||
|
||||
[wcs-olap]
|
||||
checkout = git@git.entrouvert.org:wcs-olap.git
|
||||
|
||||
[welco]
|
||||
checkout = git@git.entrouvert.org:welco.git
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
@Library('eo-jenkins-lib@master') import eo.Utils
|
||||
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Unit Tests') {
|
||||
steps {
|
||||
sh 'echo "no test implemented"'
|
||||
}
|
||||
}
|
||||
stage('Packaging') {
|
||||
steps {
|
||||
script {
|
||||
if (env.JOB_NAME == 'publik-builder' && env.GIT_BRANCH == 'origin/master') {
|
||||
sh 'sudo -H -u eobuilder /usr/local/bin/eobuilder publik-builder'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
utils = new Utils()
|
||||
utils.mail_notify(currentBuild, env, 'admin+adminsys@entrouvert.com')
|
||||
}
|
||||
}
|
||||
success {
|
||||
cleanWs()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
.PHONY: clean name version name fullname
|
||||
|
||||
NAME=$(shell basename $(CURDIR))
|
||||
VERSION=`git describe | sed 's/^debian\///' | sed 's/v//'`
|
||||
DIST_FILES = Makefile \
|
||||
publik-builder \
|
||||
flavors
|
||||
|
||||
version:
|
||||
@(echo $(VERSION))
|
||||
|
||||
name:
|
||||
@(echo $(NAME))
|
||||
|
||||
fullname:
|
||||
@(echo $(NAME)-$(VERSION))
|
||||
|
||||
clean:
|
||||
rm -rf sdist
|
||||
|
||||
dist-bzip2: dist
|
||||
cd sdist && tar cfj ../sdist/$(NAME)-$(VERSION).tar.bz2 $(NAME)-$(VERSION)
|
||||
|
||||
dist: clean
|
||||
-mkdir sdist
|
||||
rm -rf sdist/$(NAME)-$(VERSION)
|
||||
mkdir -p sdist/$(NAME)-$(VERSION)
|
||||
for i in $(DIST_FILES); do \
|
||||
cp -R "$$i" sdist/$(NAME)-$(VERSION); \
|
||||
done
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
publik-builder
|
||||
=============
|
||||
|
||||
Publik images builder.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
* debootstrap: Note you can run debootstrap from its source tree without installing it:
|
||||
|
||||
git clone https://salsa.debian.org/installer-team/debootstrap.git
|
||||
alias debootstrap=$(pwd)/debootstrap/deboostrap
|
|
@ -0,0 +1,5 @@
|
|||
publik-builder (0.1) stretch; urgency=medium
|
||||
|
||||
* Initial release
|
||||
|
||||
-- Christophe Siraut <csiraut@entrouvert.com> Tue, 04 Sep 2018 17:15:19 +0200
|
|
@ -0,0 +1 @@
|
|||
9
|
|
@ -0,0 +1,11 @@
|
|||
Source: publik-builder
|
||||
Maintainer: Christophe Siraut <csiraut@entrouvert.com>
|
||||
Section: python
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>= 9)
|
||||
Standards-Version: 4.1.3
|
||||
|
||||
Package: publik-builder
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, python3:any
|
||||
Description: Publik images builder
|
|
@ -0,0 +1,25 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: publik-common
|
||||
Source: https://www.entrouvert.com
|
||||
|
||||
Files: *
|
||||
Copyright: 2018 Christophe Siraut <csiraut@entrouvert.com>
|
||||
2018 Entrouvert Admins <admin@entrouvert.com>
|
||||
License: GPL-3.0+
|
||||
|
||||
License: GPL-3.0+
|
||||
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, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package 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 <https://www.gnu.org/licenses/>.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
|
@ -0,0 +1,7 @@
|
|||
[DEFAULT]
|
||||
cleaner = fakeroot debian/rules clean
|
||||
builder = debuild -us -uc
|
||||
|
||||
[buildpackage]
|
||||
export-dir = ../build-area
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
publik-builder /usr/bin
|
||||
flavors /var/lib/publik-builder
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/make -f
|
||||
export PYBUILD_NAME=publik-common
|
||||
|
||||
%:
|
||||
dh $@
|
|
@ -0,0 +1 @@
|
|||
3.0 (quilt)
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
# publik-bootstrap: start a Publik server
|
||||
# 2018 Entr'ouvert
|
||||
set -e
|
||||
|
||||
apt-get update
|
||||
apt-get install -yqq apt-transport-https ca-certificates wget lsb-release
|
||||
wget -O - https://deb.entrouvert.org/entrouvert.gpg | apt-key add -
|
||||
echo "deb http://deb.entrouvert.org/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/entrouvert.list
|
||||
apt-get update
|
||||
apt-get install -y publik-common
|
||||
|
||||
publik-create-users
|
||||
apt install -y postgresql-client bsd-mailx zip # libreoffice
|
||||
cp /etc/publik/publik.conf.example /etc/publik/publik.conf
|
||||
public-create-databases
|
||||
|
||||
#apt install hobo hobo-agent
|
||||
#systemctl restart supervisor
|
||||
#apt install -y authentic2-multitenant python-authentic2-auth-fc
|
||||
#apt install -y combo
|
||||
#apt install -y passerelle
|
||||
#apt install -y bijoe fargo welco chrono
|
||||
#apt install -y wcs wcs-au-quotidien
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/python3
|
||||
# Publik image builder
|
||||
# 2018 Entr'ouvert
|
||||
from contextlib import contextmanager
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import uuid
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--release', type=str, default='stretch')
|
||||
parser.add_argument('--prefix', type=str, default='publik')
|
||||
parser.add_argument('--arch', type=str, default='amd64')
|
||||
parser.add_argument('--clean', action='store_true')
|
||||
parser.add_argument('--flavor', choices=['server', 'devinst', 'vanilla'], default='server')
|
||||
parser.add_argument('--form', choices=['tar', 'xz', 'folder'], default='xz')
|
||||
args = parser.parse_args()
|
||||
|
||||
options = vars(args)
|
||||
options['mirror'] = 'http://httpredir.debian.org/debian/'
|
||||
options['tag'] = '{release}-{arch}'.format(**options)
|
||||
options['cachedir'] = '/var/cache/publik-builder'
|
||||
options['output_dir'] = os.getcwd()
|
||||
options['output'] = '{output_dir}/{prefix}-{tag}'.format(**options)
|
||||
|
||||
if os.getuid():
|
||||
raise(Exception('please with sudo (or as root)'))
|
||||
|
||||
|
||||
def run(cmd):
|
||||
subprocess.run(cmd, shell=True, check=True)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mount_chroot(path):
|
||||
run('mount -t proc /proc {}/proc'.format(path))
|
||||
run('mount --bind /sys {}/sys'.format(path))
|
||||
run('mount --bind /dev {}/dev'.format(path))
|
||||
run('mount --bind /tmp {}/tmp'.format(path))
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
run('umount {}/tmp'.format(path))
|
||||
run('umount {}/dev'.format(path))
|
||||
run('umount {}/sys'.format(path))
|
||||
run('umount {}/proc'.format(path))
|
||||
|
||||
|
||||
rootfs = os.path.join(options['cachedir'], options['tag'])
|
||||
if args.clean and os.path.isdir(rootfs):
|
||||
shutil.rmtree(rootfs)
|
||||
if not os.path.isdir(rootfs):
|
||||
if not os.path.isdir(options['cachedir']):
|
||||
os.makedirs(options['cachedir'])
|
||||
options['rootfs'] = rootfs
|
||||
run('debootstrap --foreign {release} {rootfs}'.format(**options))
|
||||
run('DEBOOTSTRAP_DIR={rootfs}/debootstrap debootstrap --second-stage --arch {arch} --second-stage-target {rootfs} {mirror}'.format(**options))
|
||||
|
||||
|
||||
workdir = os.path.join('/tmp/publik-builder', str(uuid.uuid4()))
|
||||
if not os.path.isdir('/tmp/publik-builder'):
|
||||
os.makedirs('/tmp/publik-builder')
|
||||
options['workdir'] = workdir
|
||||
print('copying base to workdir {}'.format(workdir))
|
||||
run('cp -r {} {}'.format(rootfs, workdir))
|
||||
|
||||
if args.flavor != 'none':
|
||||
if args.flavor == 'devinst':
|
||||
raise(Exception('not implemented'))
|
||||
script = '/var/lib/publik-builder/flavors/%s' % args.flavor
|
||||
if not os.path.isfile(script):
|
||||
script = './flavors/%s' % args.flavor
|
||||
if not os.path.isfile:
|
||||
raise(Exception('cannot find {}'.format(script)))
|
||||
|
||||
rscript = '{}/usr/local/bin/publik-bootstrap'.format(workdir)
|
||||
shutil.copyfile(script, rscript)
|
||||
run('chmod +x {}'.format(rscript))
|
||||
with mount_chroot(workdir):
|
||||
run('chroot {} publik-bootstrap'.format(workdir))
|
||||
run('chroot {} apt-get clean'.format(workdir))
|
||||
|
||||
|
||||
if args.form == 'tar':
|
||||
run('cd {workdir} && tar cf {output}.tar ./'.format(**options))
|
||||
elif args.form == 'xz':
|
||||
run('cd {workdir} && tar cfJ {output}.tar.xz ./'.format(**options))
|
||||
elif args.form == 'folder':
|
||||
folder = '{output_dir}/{prefix}-{tag}'.format(**options)
|
||||
shutil.move(workdir, folder)
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/python3
|
||||
import argparse
|
||||
import cryptography
|
||||
import glob
|
||||
import os
|
||||
import paramiko
|
||||
import warnings
|
||||
warnings.simplefilter("ignore", cryptography.utils.CryptographyDeprecationWarning)
|
||||
|
||||
|
||||
def connection(hostname, username, password=None, keyfile=None):
|
||||
if not keyfile:
|
||||
keyfile = os.path.expanduser('~/.ssh/id_rsa')
|
||||
key = paramiko.RSAKey.from_private_key_file(keyfile)
|
||||
client = paramiko.SSHClient()
|
||||
client.load_system_host_keys()
|
||||
client.connect(hostname, username='csiraut', password=password, pkey=key)
|
||||
return paramiko.SFTPClient.from_transport(client.get_transport())
|
||||
|
||||
|
||||
def validate_local_path(path):
|
||||
if not os.path.exists(path) or not os.path.isdir(path):
|
||||
raise(Exception('Directory %s does not exist' % path))
|
||||
|
||||
|
||||
def validate_remote_path(sftp, path):
|
||||
lstat = sftp.lstat(path)
|
||||
mode = oct(lstat.st_mode)[5]
|
||||
if mode not in ['5', '7']:
|
||||
raise(Exception('Remote path is not a folder or not writable'))
|
||||
|
||||
|
||||
def parse_location(loc):
|
||||
hostname, username, path = None, None, loc
|
||||
if '@' in loc and ':' in loc:
|
||||
username, remaning = loc.split('@')
|
||||
hostname, path = remaning.split(':')
|
||||
return hostname, username, path
|
||||
|
||||
|
||||
def get(hostname, username, remotepath, localpath, password=None, keyfile=None):
|
||||
validate_local_path(localpath)
|
||||
sftp = connection(hostname, username, password=password, keyfile=keyfile)
|
||||
validate_remote_path(sftp, remotepath)
|
||||
|
||||
dirlist = sftp.listdir_attr(remotepath)
|
||||
filelist = [x.filename for x in dirlist if oct(x.st_mode)[5] not in ('5', '7')]
|
||||
for f in filelist:
|
||||
if args.verbose:
|
||||
print('syncing %s to %s' % (remotepath, localpath))
|
||||
remotefilepath = '%s/%s' % (remotepath, f)
|
||||
localfilepath = '%s/%s' % (localpath, f)
|
||||
sftp.get(remotefilepath, localfilepath)
|
||||
if args.delete:
|
||||
if args.verbose:
|
||||
print('removing %s' % remotefilepath)
|
||||
sftp.remove(remotefilepath)
|
||||
|
||||
|
||||
def put(hostname, username, remotepath, localpath, password=None, keyfile=None):
|
||||
validate_local_path(localpath)
|
||||
sftp = connection(hostname, username, password=password, keyfile=keyfile)
|
||||
validate_remote_path(sftp, remotepath)
|
||||
|
||||
filelist = [f for f in glob.glob('%s/*' % localpath) if not os.path.isdir(f)]
|
||||
for f in filelist:
|
||||
remotefilepath = '%s/%s' % (remotepath, f.split('/')[-1])
|
||||
if args.verbose:
|
||||
print('syncing %s to %s' % (f, remotefilepath))
|
||||
sftp.put(f, remotefilepath)
|
||||
if args.delete:
|
||||
if args.verbose:
|
||||
print('removing %s' % f)
|
||||
os.remove(f)
|
||||
|
||||
|
||||
def main(args):
|
||||
orig = parse_location(args.origin)
|
||||
dest = parse_location(args.destination)
|
||||
if (orig[0] and dest[0]) or (not orig[1] and not dest[1]) or \
|
||||
((orig[1] and '@' not in orig[1]) and (dest[1] and '@' not in dest[1])):
|
||||
raise(Exception('Please provide one remote location like this: user@server:/path/to/direction'))
|
||||
if orig[1]:
|
||||
action, hostname, username, remotepath, localpath = 'get', orig[0], orig[1], orig[2], dest[2]
|
||||
else:
|
||||
action, hostname, username, remotepath, localpath = 'put', dest[0], dest[1], dest[2], orig[2]
|
||||
|
||||
globals()[action](hostname, username, remotepath, localpath, args.password, args.keyfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='sftp.py — secure file transfer program')
|
||||
parser.add_argument('origin', help='directory holding files to sync')
|
||||
parser.add_argument('destination', help='target directory')
|
||||
parser.add_argument('--keyfile')
|
||||
parser.add_argument('--password')
|
||||
parser.add_argument('--delete', action='store_true', help='remove source file(s) when transfered')
|
||||
parser.add_argument('--verbose', action='store_true')
|
||||
args = parser.parse_args()
|
||||
main(args)
|
Reference in New Issue