Added orchestration.Server remote status retrieval
This commit is contained in:
parent
e74964417a
commit
7578c47c9a
26
TODO.md
26
TODO.md
|
@ -460,3 +460,29 @@ mkhomedir_helper or create ssh homes with bash.rc and such
|
|||
|
||||
|
||||
# POSTFIX web traffic monitor '": uid=" from=<%(user)s>'
|
||||
|
||||
# orchestra.server PING/SSH+uptime status
|
||||
class ServerState(models.Model):
|
||||
server = models.OneToOneField(Server)
|
||||
ping = models.CharField(max_length=256)
|
||||
uptime = models.CharField(max_length=256)
|
||||
from orchestra.contrib.orchestration.models import Server
|
||||
from orchestra.utils.sys import run, sshrun, joinall
|
||||
def retrieve_state(servers):
|
||||
uptimes = []
|
||||
pings = []
|
||||
for server in servers:
|
||||
address = server.get_address()
|
||||
ping = run('ping -c 1 %s' % address, async=True)
|
||||
pings.append(ping)
|
||||
uptime = sshrun(address, 'uptime', persist=True, async=True)
|
||||
uptimes.append(uptime)
|
||||
|
||||
pings = joinall(pings, silent=True)
|
||||
uptimes = joinall(uptimes, silent=True)
|
||||
for ping in pings:
|
||||
print(ping.stdout.splitlines()[-1])
|
||||
|
||||
for uptime in uptimes:
|
||||
print(uptime.stdout)
|
||||
retrieve_state(Server.objects.all())
|
||||
|
|
|
@ -11,6 +11,7 @@ from . import settings, helpers
|
|||
from .backends import ServiceBackend
|
||||
from .forms import RouteForm
|
||||
from .models import Server, Route, BackendLog, BackendOperation
|
||||
from .utils import retrieve_state
|
||||
from .widgets import RouteBackendSelect
|
||||
|
||||
|
||||
|
@ -167,9 +168,25 @@ class BackendLogAdmin(admin.ModelAdmin):
|
|||
|
||||
|
||||
class ServerAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'address', 'os')
|
||||
list_display = ('name', 'address', 'os', 'display_ping', 'display_uptime')
|
||||
list_filter = ('os',)
|
||||
|
||||
def display_ping(self, instance):
|
||||
return self._remote_state[instance.pk][0]
|
||||
display_ping.short_description = _("Ping")
|
||||
display_ping.allow_tags = True
|
||||
|
||||
def display_uptime(self, instance):
|
||||
return self._remote_state[instance.pk][1]
|
||||
display_uptime.short_description = _("Uptime")
|
||||
display_uptime.allow_tags = True
|
||||
|
||||
def get_queryset(self, request):
|
||||
""" Order by structured name and imporve performance """
|
||||
qs = super(ServerAdmin, self).get_queryset(request)
|
||||
if request.method == 'GET' and request.resolver_match.func.__name__ == 'changelist_view':
|
||||
self._remote_state = retrieve_state(qs)
|
||||
return qs
|
||||
|
||||
admin.site.register(Server, ServerAdmin)
|
||||
admin.site.register(BackendLog, BackendLogAdmin)
|
||||
|
|
|
@ -28,7 +28,7 @@ class Server(models.Model):
|
|||
validators=[OrValidator(validate_ip_address, validate_hostname)],
|
||||
null=True, unique=True, help_text=_(
|
||||
"Optional IP address or domain name. Name field will be used if not provided.<br>"
|
||||
"If the IP address never change you can set this field and save DNS requests."))
|
||||
"If the IP address never changes you can set this field and save DNS requests."))
|
||||
description = models.TextField(_("description"), blank=True)
|
||||
os = models.CharField(_("operative system"), max_length=32,
|
||||
choices=settings.ORCHESTRATION_OS_CHOICES,
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
from orchestra.utils.sys import run, sshrun, join
|
||||
|
||||
|
||||
def retrieve_state(servers):
|
||||
uptimes = []
|
||||
pings = []
|
||||
for server in servers:
|
||||
address = server.get_address()
|
||||
ping = run('ping -c 1 -w 1 %s' % address, async=True)
|
||||
pings.append(ping)
|
||||
uptime = sshrun(address, 'uptime', persist=True, async=True, options={'ConnectTimeout': 1})
|
||||
uptimes.append(uptime)
|
||||
|
||||
state = {}
|
||||
for server, ping, uptime in zip(servers, pings, uptimes):
|
||||
ping = join(ping, silent=True)
|
||||
ping = ping.stdout.splitlines()[-1].decode()
|
||||
if ping.startswith('rtt'):
|
||||
ping = '%s ms' % ping.split('/')[4]
|
||||
else:
|
||||
ping = '<span style="color:red"><b>offline<b></span>'
|
||||
|
||||
uptime = join(uptime, silent=True)
|
||||
uptime = uptime.stdout.decode().split()
|
||||
if uptime:
|
||||
uptime = 'Up %s %s load %s %s %s' % (uptime[2], uptime[3], uptime[-3], uptime[-2], uptime[-1])
|
||||
else:
|
||||
uptime = '<span style="color:red"><b>Timeout<b></span>'
|
||||
state[server.pk] = (ping, uptime)
|
||||
|
||||
return state
|
|
@ -348,6 +348,17 @@ class PHPUploadMaxFileSize(PHPAppOption):
|
|||
regex = r'^[0-9]{1,3}M$'
|
||||
|
||||
|
||||
class PHPUploadTmpDir(PHPAppOption):
|
||||
name = 'upload_tmp_dir'
|
||||
verbose_name = _("Upload tmp dir")
|
||||
help_text = _("The temporary directory used for storing files when doing file upload. "
|
||||
"Must be writable by whatever user PHP is running as. "
|
||||
"If not specified PHP will use the system's default.<br>"
|
||||
"If the directory specified here is not writable, PHP falls back to the "
|
||||
"system default temporary directory. If open_basedir is on, then the system "
|
||||
"default directory must be allowed for an upload to succeed.")
|
||||
regex = r'.*$'
|
||||
|
||||
class PHPZendExtension(PHPAppOption):
|
||||
name = 'zend_extension'
|
||||
verbose_name = _("Zend extension")
|
||||
|
|
|
@ -251,6 +251,7 @@ WEBAPPS_ENABLED_OPTIONS = Setting('WEBAPPS_ENABLED_OPTIONS', (
|
|||
'orchestra.contrib.webapps.options.PHPSuhosinSimulation',
|
||||
'orchestra.contrib.webapps.options.PHPSuhosinExecutorIncludeWhitelist',
|
||||
'orchestra.contrib.webapps.options.PHPUploadMaxFileSize',
|
||||
'orchestra.contrib.webapps.options.PHPUploadTmpDir',
|
||||
'orchestra.contrib.webapps.options.PHPZendExtension',
|
||||
),
|
||||
# lazy loading
|
||||
|
|
|
@ -143,6 +143,14 @@ def join(iterator, display=False, silent=False, valid_codes=(0,)):
|
|||
return out
|
||||
|
||||
|
||||
def joinall(iterators, **kwargs):
|
||||
results = []
|
||||
for iterator in iterators:
|
||||
out = join(iterator, **kwargs)
|
||||
results.append(out)
|
||||
return results
|
||||
|
||||
|
||||
def run(command, display=False, valid_codes=(0,), silent=False, stdin=b'', async=False):
|
||||
iterator = runiterator(command, display, stdin)
|
||||
next(iterator)
|
||||
|
@ -151,22 +159,24 @@ def run(command, display=False, valid_codes=(0,), silent=False, stdin=b'', async
|
|||
return join(iterator, display=display, silent=silent, valid_codes=valid_codes)
|
||||
|
||||
|
||||
def sshrun(addr, command, *args, executable='bash', persist=False, **kwargs):
|
||||
from .. import settings
|
||||
options = [
|
||||
'stricthostkeychecking=no',
|
||||
'BatchMode=yes',
|
||||
'EscapeChar=none',
|
||||
]
|
||||
def sshrun(addr, command, *args, executable='bash', persist=False, options=None, **kwargs):
|
||||
base_options = {
|
||||
'stricthostkeychecking': 'no',
|
||||
'BatchMode': 'yes',
|
||||
'EscapeChar': 'none',
|
||||
}
|
||||
if persist:
|
||||
options.extend((
|
||||
'ControlMaster=auto',
|
||||
'ControlPersist=yes',
|
||||
'ControlPath=' + settings.ORCHESTRA_SSH_CONTROL_PATH,
|
||||
))
|
||||
from .. import settings
|
||||
base_options.update({
|
||||
'ControlMaster': 'auto',
|
||||
'ControlPersist': 'yes',
|
||||
'ControlPath': settings.ORCHESTRA_SSH_CONTROL_PATH,
|
||||
})
|
||||
base_options.update(options or {})
|
||||
options = ['%s=%s' % (k, v) for k, v in base_options.items()]
|
||||
options = ' -o '.join(options)
|
||||
cmd = 'ssh -o {options} -C root@{addr} {executable}'.format(options=options, addr=addr,
|
||||
executable=executable)
|
||||
cmd = 'ssh -o {options} -C root@{addr} {executable}'.format(
|
||||
options=options, addr=addr, executable=executable)
|
||||
return run(cmd, *args, stdin=command.encode('utf8'), **kwargs)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue