mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
This is a major update coming all at once from master-next branch master-next branch was started with --orphan option which is basically a new branch without history. The major changes are: - repackaging - cleanup the directory tree - rewritte setup.py to allow install from deb file or pypi (pip install) - add a Makefile to make things (like building a deb) easier - review all debian files Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
289 lines
9.1 KiB
Python
Executable File
289 lines
9.1 KiB
Python
Executable File
#!/usr/bin/python
|
|
#
|
|
# Copyright 2017 Cumulus Networks, Inc. All rights reserved.
|
|
# Authors:
|
|
# Roopa Prabhu, roopa@cumulusnetworks.com
|
|
# Julien Fortin, julien@cumulusnetworks.com
|
|
#
|
|
# ifupdown2 --
|
|
# tool to configure network interfaces
|
|
#
|
|
|
|
import os
|
|
import re
|
|
import json
|
|
import fcntl
|
|
import struct
|
|
import signal
|
|
import socket
|
|
import daemon
|
|
import select
|
|
import datetime
|
|
import threading
|
|
|
|
try:
|
|
import ifupdown2.ifupdown.argv
|
|
|
|
from ifupdown2.ifupdown.log import log
|
|
from ifupdown2.ifupdown.main import Ifupdown2
|
|
except ImportError:
|
|
import ifupdown.argv
|
|
|
|
from ifupdown.log import log
|
|
from ifupdown.main import Ifupdown2
|
|
|
|
|
|
class Daemon:
|
|
shutdown_event = threading.Event()
|
|
|
|
def __init__(self):
|
|
self.uds = None
|
|
self.context = None
|
|
self.working_directory = '/var/run/ifupdown2d/'
|
|
self.server_address = '/var/run/ifupdown2d/uds'
|
|
|
|
if not os.path.exists(self.working_directory):
|
|
log.info('creating %s' % self.working_directory)
|
|
os.makedirs(self.working_directory, mode=0755)
|
|
|
|
if os.path.exists(self.server_address):
|
|
log.info('removing uds %s' % self.server_address)
|
|
os.remove(self.server_address)
|
|
|
|
self.context = daemon.DaemonContext(
|
|
working_directory=self.working_directory,
|
|
signal_map={
|
|
signal.SIGINT: self.signal_handler,
|
|
signal.SIGTERM: self.signal_handler,
|
|
signal.SIGQUIT: self.signal_handler,
|
|
},
|
|
umask=0o22
|
|
)
|
|
|
|
try:
|
|
self.SO_PEERCRED = socket.SO_PEERCRED
|
|
except AttributeError:
|
|
# powerpc is the only non-generic we care about. alpha, mips,
|
|
# sparc, and parisc also have non-generic values.
|
|
machine = os.uname()[4]
|
|
if re.search(r'^(ppc|powerpc)', machine):
|
|
self.SO_PASSCRED = 20
|
|
self.SO_PEERCRED = 21
|
|
else:
|
|
self.SO_PASSCRED = 16
|
|
self.SO_PEERCRED = 17
|
|
|
|
log.info('daemonizing ifupdown2d...')
|
|
self.context.open()
|
|
|
|
log.info('preloading all necessary modules')
|
|
self.preload_imports()
|
|
|
|
try:
|
|
log.info('opening UNIX socket')
|
|
self.uds = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
fcntl.fcntl(self.uds.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
|
except Exception as e:
|
|
raise Exception('socket: %s' % str(e))
|
|
try:
|
|
self.uds.bind(self.server_address)
|
|
except Exception as e:
|
|
raise Exception('bind: %s' % str(e))
|
|
try:
|
|
self.uds.setsockopt(socket.SOL_SOCKET, self.SO_PASSCRED, 1)
|
|
except Exception as e:
|
|
raise Exception('setsockopt: %s' % str(e))
|
|
try:
|
|
self.uds.listen(1)
|
|
except Exception as e:
|
|
raise Exception('listen: %s' % str(e))
|
|
os.chmod(self.server_address, 0777)
|
|
|
|
def __del__(self):
|
|
if self.context:
|
|
self.context.close()
|
|
if self.uds:
|
|
self.uds.close()
|
|
|
|
@staticmethod
|
|
def preload_imports():
|
|
"""
|
|
preloading all the necessary modules
|
|
at first will increase performances
|
|
"""
|
|
try:
|
|
import io
|
|
import pdb
|
|
import imp
|
|
import sets
|
|
import json
|
|
import glob
|
|
import time
|
|
import copy
|
|
import errno
|
|
import pprint
|
|
import atexit
|
|
import ipaddr
|
|
import cPickle
|
|
import logging
|
|
import argparse
|
|
import StringIO
|
|
import datetime
|
|
import traceback
|
|
import itertools
|
|
import subprocess
|
|
import argcomplete
|
|
import collections
|
|
import ConfigParser
|
|
import pkg_resources
|
|
|
|
import ifupdown2.ifupdown.exceptions
|
|
import ifupdown2.ifupdown.graph
|
|
import ifupdown2.ifupdown.iface
|
|
import ifupdown2.ifupdown.iff
|
|
import ifupdown2.ifupdown.ifupdownbase
|
|
import ifupdown2.ifupdown.ifupdownbase
|
|
import ifupdown2.ifupdown.ifupdownconfig
|
|
import ifupdown2.ifupdown.ifupdownflags
|
|
import ifupdown2.ifupdown.ifupdownmain
|
|
import ifupdown2.ifupdown.netlink
|
|
import ifupdown2.ifupdown.networkinterfaces
|
|
import ifupdown2.ifupdown.policymanager
|
|
import ifupdown2.ifupdown.scheduler
|
|
import ifupdown2.ifupdown.statemanager
|
|
import ifupdown2.ifupdown.template
|
|
import ifupdown2.ifupdown.utils
|
|
|
|
import ifupdown2.ifupdownaddons.cache
|
|
import ifupdown2.ifupdownaddons.dhclient
|
|
import ifupdown2.ifupdownaddons.mstpctlutil
|
|
import ifupdown2.ifupdownaddons.LinkUtils
|
|
import ifupdown2.ifupdownaddons.modulebase
|
|
import ifupdown2.ifupdownaddons.systemutils
|
|
import ifupdown2.ifupdownaddons.utilsbase
|
|
except ImportError, e:
|
|
raise ImportError('%s - required module not found' % str(e))
|
|
|
|
@staticmethod
|
|
def signal_handler(sig, frame):
|
|
log.info('received %s' % 'SIGINT' if sig == signal.SIGINT else 'SIGTERM')
|
|
Daemon.shutdown_event.set()
|
|
|
|
@staticmethod
|
|
def user_waiting_for_reply():
|
|
return not log.is_syslog()
|
|
|
|
def run(self):
|
|
try:
|
|
while True:
|
|
if Daemon.shutdown_event.is_set():
|
|
log.info("shutdown signal RXed, breaking out loop")
|
|
break
|
|
|
|
try:
|
|
(client_socket, client_address) = self.uds.accept()
|
|
except socket.error as e:
|
|
log.error(str(e))
|
|
break
|
|
|
|
pid = os.fork()
|
|
if pid == 0:
|
|
exit(self.ifupdown2(client_socket))
|
|
else:
|
|
log.tx_data(json.dumps({'pid': pid}), socket=client_socket)
|
|
|
|
start = datetime.datetime.now()
|
|
status = os.WEXITSTATUS(os.waitpid(pid, 0)[1])
|
|
end = datetime.datetime.now()
|
|
|
|
log.tx_data(json.dumps({'status': status}), socket=client_socket)
|
|
client_socket.close()
|
|
|
|
log.info('exit status %d - in %ssecs'
|
|
% (status, (end - start).total_seconds()))
|
|
|
|
except Exception as e:
|
|
log.error(e)
|
|
self.uds.close()
|
|
|
|
def get_client_uid(self, client_socket):
|
|
creds = client_socket.getsockopt(socket.SOL_SOCKET, self.SO_PEERCRED, struct.calcsize('3i'))
|
|
(pid, uid, gid) = struct.unpack('3i', creds)
|
|
log.debug('client uid %d' % uid)
|
|
return uid
|
|
|
|
@staticmethod
|
|
def get_client_request(client_socket):
|
|
"""
|
|
This function handles requests of any length.
|
|
|
|
if the received json is longer than 65k it will be truncated
|
|
several calls to recv will be needed, we store the data until
|
|
we can decode them with the json library.
|
|
"""
|
|
data = []
|
|
while True:
|
|
log.debug('waiting for request on client socket')
|
|
ready = select.select([client_socket], [], [])
|
|
|
|
if ready and ready[0] and ready[0][0] == client_socket:
|
|
# data available start reading
|
|
raw_data = client_socket.recv(65536)
|
|
|
|
try:
|
|
return json.loads(raw_data)
|
|
except ValueError:
|
|
# the json is incomplete
|
|
data.append(raw_data)
|
|
|
|
if len(data) > 1:
|
|
try:
|
|
return json.loads(''.join(data))
|
|
except ValueError:
|
|
pass
|
|
|
|
def ifupdown2(self, client_socket):
|
|
try:
|
|
fcntl.fcntl(client_socket.fileno(), fcntl.F_SETFD, fcntl.FD_CLOEXEC)
|
|
|
|
ifupdown2 = Ifupdown2(daemon=True, uid=self.get_client_uid(client_socket))
|
|
ifupdown2.set_signal_handlers()
|
|
|
|
request = self.get_client_request(client_socket)
|
|
log.info('request: %s' % request['argv'])
|
|
|
|
ifupdown2.parse_argv(request['argv'])
|
|
# adjust the logger with argv
|
|
ifupdown2.update_logger(socket=client_socket)
|
|
|
|
try:
|
|
status = ifupdown2.main(request['stdin'])
|
|
except Exception as e:
|
|
log.error(str(e))
|
|
status = 1
|
|
|
|
except ifupdown2.ifupdown.argv.ArgvParseError as e:
|
|
log.update_current_logger(syslog=False, verbose=True, debug=False)
|
|
log.set_socket(client_socket)
|
|
e.log_error()
|
|
status = 1
|
|
except Exception as e:
|
|
log.error(e)
|
|
status = 1
|
|
|
|
log.flush()
|
|
log.set_socket(None)
|
|
client_socket.close()
|
|
return status
|
|
|
|
|
|
if __name__ == '__main__':
|
|
try:
|
|
Daemon().run()
|
|
except Exception as e:
|
|
print e
|
|
log.error(str(e))
|
|
import traceback
|
|
log.error(traceback.format_exc())
|
|
exit(1)
|