slapos-theia 5.55 KB
Newer Older
Yusei Tahara's avatar
Yusei Tahara committed
1 2 3 4 5 6 7 8 9 10 11 12 13
#!/usr/bin/python3

import os
import sys
import time
import subprocess

OCF_SUCCESS = 0
OCF_ERR_GENERIC = 1
OCF_NOT_RUNNING = 7

action = sys.argv[1]

Yusei Tahara's avatar
Yusei Tahara committed
14 15
instance_root = os.getenv('OCF_RESKEY_instance_root') or ''
instance_root_b = instance_root.encode('utf8')
Yusei Tahara's avatar
Yusei Tahara committed
16 17 18 19
part_id = os.getenv('OCF_RESKEY_part_id')
slappart = 'slappart%s' % part_id
slappart_b = slappart.encode('utf8')
slapuser = 'slapuser%s' % part_id
20 21 22 23 24 25 26 27
serious_service_list = []
serious_services_text = os.getenv('OCF_RESKEY_serious_services', None)
if serious_services_text:
  serious_service_list = serious_services_text.split(',')
autostart_service_list = []
autostart_services_text = os.getenv('OCF_RESKEY_autostart_services', None)
if autostart_services_text:
  autostart_service_list = autostart_services_text.split(',')
Yusei Tahara's avatar
Yusei Tahara committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#kumofs_gateway,kumofs_manager,kumofs_server,mariadb,zeo,zope,haproxy


def splitLine(line):
  return [item for item in line.split(b' ') if item]

def runCommand(*args):
  return subprocess.run(args, capture_output=True)

def runSlapOS(*args):
  return runCommand('slapos', *args)

def checkTheiaStatus(target_status):
  completed_process = runSlapOS('node')
  for line in completed_process.stdout.split(b'\n'):
    if line.startswith(slappart_b):
      split_line = splitLine(line)
      if (split_line[0].startswith(slappart_b + b':theia-instance') and
          split_line[1].decode('utf8') == target_status):
        return True
  return False

def isTheiaRunning():
  return checkTheiaStatus('RUNNING')

def isTheiaStopped():
  return checkTheiaStatus('STOPPED')

def runSlapOSInTheia(*args):
  return runCommand('sudo', '-u', slapuser,
Yusei Tahara's avatar
Yusei Tahara committed
58
                    '%s/%s/srv/runner/bin/slapos' % (instance_root, slappart),
Yusei Tahara's avatar
Yusei Tahara committed
59 60 61 62
                    *args)

def checkAppStatus(target_status):
  completed_process = runSlapOSInTheia('node')
Yusei Tahara's avatar
Yusei Tahara committed
63
  if completed_process.stdout == b'unix://%s/%s/srv/runner/instance/sv.sock no such file\n' % (instance_root_b, slappart_b):
Yusei Tahara's avatar
Yusei Tahara committed
64 65 66 67
    if target_status == 'STOPPED':
      return True
    else:
      return False
68
  service_data_list = []
Yusei Tahara's avatar
Yusei Tahara committed
69 70 71 72 73 74
  for line in completed_process.stdout.split(b'\n'):
    if not line:
      continue
    split_line = splitLine(line)
    if split_line[0].decode('utf8') == 'watchdog':
      continue
75
    service_id = split_line[0].decode('utf8')
Yusei Tahara's avatar
Yusei Tahara committed
76 77
    service_name = split_line[0].split(b':')[1].split(b'-')[0].decode('utf8')
    current_status = split_line[1].decode('utf8')
78 79 80
    service_data_list.append((service_id, service_name, current_status))
  for service_id, service_name, current_status in service_data_list:
    if service_name in serious_service_list:
Yusei Tahara's avatar
Yusei Tahara committed
81
      if current_status != target_status:
82 83 84 85 86
        return False
  if target_status == 'RUNNING' and autostart_service_list:
    for service_id, service_name, current_status in service_data_list:
      if current_status == 'EXITED' and service_name in autostart_service_list:
        runSlapOSInTheia('node', 'start', service_id)
Yusei Tahara's avatar
Yusei Tahara committed
87 88 89 90 91 92 93 94 95 96
  return True

def isAppRunning():
  return checkAppStatus('RUNNING')

def isAppStopped():
  return checkAppStatus('STOPPED')

def monitor():
  result = OCF_ERR_GENERIC
Yusei Tahara's avatar
Yusei Tahara committed
97 98
  if not os.path.exists(instance_root):
    result = OCF_NOT_RUNNING
Yusei Tahara's avatar
Yusei Tahara committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
  try:
    if isTheiaRunning() and isAppRunning():
      result = OCF_SUCCESS
    elif isTheiaStopped() and isAppStopped():
      result = OCF_NOT_RUNNING
  except:
    pass
  sys.exit(result)

def start():
  result = OCF_ERR_GENERIC
  try:
    while not isTheiaRunning():
      runSlapOS('node', 'start', slappart + ':*')
      time.sleep(3)
    while not isAppRunning():
      runSlapOSInTheia('node', 'start', 'all')
      time.sleep(3)
    result = OCF_SUCCESS
  except:
    pass
  sys.exit(result)

def stop():
  result = OCF_ERR_GENERIC
  try:
    while not isAppStopped():
      runSlapOSInTheia('node', 'stop', 'all')
      time.sleep(3)
    while not isTheiaStopped():
      runSlapOS('node', 'stop', slappart + ':*')
      time.sleep(3)
    result = OCF_SUCCESS
  except:
    pass
  sys.exit(result)

def metadata():
  print ('''\
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="slapos-theia">
<version>1.0</version>
<longdesc lang="en">
This is the resource agent for SlapOS Theia.
</longdesc>
<shortdesc lang="en">Manages SlapOS Theia instance</shortdesc>

<parameters>
Yusei Tahara's avatar
Yusei Tahara committed
148 149 150 151 152 153 154
<parameter name="instance_root" unique="0" required="1">
<longdesc>
Instance Root Directory Path
</longdesc>
<shortdesc>Instance Root</shortdesc>
<content type="string"/>
</parameter>
Yusei Tahara's avatar
Yusei Tahara committed
155 156 157 158 159 160 161
<parameter name="part_id" unique="1" required="1">
<longdesc>
Computer Partition ID, slappartX
</longdesc>
<shortdesc>Partition ID</shortdesc>
<content type="integer"/>
</parameter>
162 163 164 165 166 167 168 169 170
<parameter name="serious_services" unique="0" required="0">
<longdesc>
Serious service names separated by comma
If serious service fails, then this resource is considered as failed.
</longdesc>
<shortdesc>Serious service names</shortdesc>
<content type="string"/>
</parameter>
<parameter name="autostart_services" unique="0" required="0">
Yusei Tahara's avatar
Yusei Tahara committed
171
<longdesc>
172 173 174
Auto-start service names separated by comma
If auto-start service becomes `EXITED`, then `slapos node start` is executed
automatically and it is not considered as failed.
Yusei Tahara's avatar
Yusei Tahara committed
175
</longdesc>
176
<shortdesc>Auto-start service names</shortdesc>
Yusei Tahara's avatar
Yusei Tahara committed
177 178 179 180 181 182 183
<content type="string"/>
</parameter>
</parameters>

<actions>
<action name="start"   timeout="60s" />
<action name="stop"    timeout="60s" />
184
<action name="monitor" depth="0"  timeout="30s" interval="60s" />
Yusei Tahara's avatar
Yusei Tahara committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198
<action name="meta-data"  timeout="5s" />
</actions>
</resource-agent>
''')
  sys.exit(OCF_SUCCESS)

if action == 'monitor':
  monitor()
elif action == 'start':
  start()
elif action == 'stop':
  stop()
elif action == 'meta-data':
  metadata()