163 lines
4.5 KiB
Python
Executable File
163 lines
4.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import json
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
import yaml
|
|
|
|
|
|
CONF_FILE = os.environ.get('HEAT_SHELL_CONFIG',
|
|
'/var/run/heat-config/heat-config')
|
|
|
|
DOCKER_CMD = os.environ.get('HEAT_DOCKER_CMD', 'docker')
|
|
|
|
|
|
log = None
|
|
|
|
|
|
def main(argv=sys.argv):
|
|
global log
|
|
log = logging.getLogger('heat-config')
|
|
handler = logging.StreamHandler(sys.stderr)
|
|
handler.setFormatter(
|
|
logging.Formatter(
|
|
'[%(asctime)s] (%(name)s) [%(levelname)s] %(message)s'))
|
|
log.addHandler(handler)
|
|
log.setLevel('DEBUG')
|
|
|
|
if not os.path.exists(CONF_FILE):
|
|
log.warning('No config file %s' % CONF_FILE)
|
|
return 1
|
|
|
|
try:
|
|
configs = json.load(open(CONF_FILE))
|
|
except ValueError as e:
|
|
log.warning('Could not load config json: %s' % e)
|
|
return 1
|
|
|
|
cmd_configs = list(build_configs(configs))
|
|
try:
|
|
delete_missing_configs(cmd_configs)
|
|
except Exception as e:
|
|
log.exception(e)
|
|
try:
|
|
rename_containers()
|
|
except Exception as e:
|
|
log.exception(e)
|
|
|
|
|
|
def build_configs(configs):
|
|
for c in configs:
|
|
if c['group'] != 'docker-cmd':
|
|
continue
|
|
if not isinstance(c['config'], dict):
|
|
# convert config to dict
|
|
c['config'] = yaml.safe_load(c['config'])
|
|
yield c
|
|
|
|
|
|
def delete_missing_configs(configs):
|
|
config_ids = [c['id'] for c in configs]
|
|
for conf_id in current_config_ids():
|
|
if conf_id not in config_ids:
|
|
log.debug('%s no longer exists, deleting containers' % conf_id)
|
|
remove_containers(conf_id)
|
|
|
|
|
|
def execute(cmd):
|
|
log.debug(' '.join(cmd))
|
|
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
cmd_stdout, cmd_stderr = subproc.communicate()
|
|
return cmd_stdout, cmd_stderr, subproc.returncode
|
|
|
|
|
|
def current_config_ids():
|
|
# List all config_id labels for containers managed by docker-cmd
|
|
cmd = [
|
|
DOCKER_CMD, 'ps', '-a',
|
|
'--filter', 'label=managed_by=docker-cmd',
|
|
'--format', '{{.Label "config_id"}}'
|
|
]
|
|
cmd_stdout, cmd_stderr, returncode = execute(cmd)
|
|
if returncode != 0:
|
|
return set()
|
|
return set(cmd_stdout.split())
|
|
|
|
|
|
def remove_containers(conf_id):
|
|
cmd = [
|
|
DOCKER_CMD, 'ps', '-q', '-a',
|
|
'--filter', 'label=managed_by=docker-cmd',
|
|
'--filter', 'label=config_id=%s' % conf_id
|
|
]
|
|
cmd_stdout, cmd_stderr, returncode = execute(cmd)
|
|
if returncode == 0:
|
|
for container in cmd_stdout.split():
|
|
remove_container(container)
|
|
|
|
|
|
def remove_container(container):
|
|
cmd = [DOCKER_CMD, 'rm', '-f', container]
|
|
cmd_stdout, cmd_stderr, returncode = execute(cmd)
|
|
if returncode != 0:
|
|
log.error('Error removing container: %s' % container)
|
|
log.error(cmd_stderr)
|
|
|
|
|
|
def rename_containers():
|
|
# list every container name, and its container_name label
|
|
cmd = [
|
|
DOCKER_CMD, 'ps', '-a',
|
|
'--format', '{{.Names}} {{.Label "container_name"}}'
|
|
]
|
|
cmd_stdout, cmd_stderr, returncode = execute(cmd)
|
|
if returncode != 0:
|
|
return
|
|
|
|
lines = cmd_stdout.split("\n")
|
|
current_containers = []
|
|
need_renaming = {}
|
|
for line in lines:
|
|
entry = line.split()
|
|
if not entry:
|
|
continue
|
|
current_containers.append(entry[0])
|
|
|
|
# ignore if container_name label not set
|
|
if len(entry) < 2:
|
|
continue
|
|
|
|
# ignore if desired name is already actual name
|
|
if entry[0] == entry[-1]:
|
|
continue
|
|
|
|
need_renaming[entry[0]] = entry[-1]
|
|
|
|
for current, desired in sorted(need_renaming.items()):
|
|
if desired in current_containers:
|
|
log.info('Cannot rename "%s" since "%s" still exists' % (
|
|
current, desired))
|
|
else:
|
|
cmd = [DOCKER_CMD, 'rename', current, desired]
|
|
execute(cmd)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv))
|