Compare commits

..

6 commits

Author SHA1 Message Date
Emmanuel Garette
14a2cc65f9 better config change detection 2022-10-17 18:52:42 +02:00
Emmanuel Garette
8895c3ee9e machinectl: add enabled 2022-10-17 18:51:54 +02:00
Emmanuel Garette
de48994d76 ansible: can delete old image before rebuild 2022-10-17 18:51:04 +02:00
Emmanuel Garette
34d277d80f src/risotto/image.py: display depends if failed 2022-10-17 18:49:34 +02:00
Emmanuel Garette
74878cae0f split update_images and diagnose 2022-10-17 18:48:32 +02:00
Emmanuel Garette
b9be6491cc add diagnose command 2022-10-17 18:44:00 +02:00
9 changed files with 122 additions and 58 deletions

View file

@ -30,21 +30,30 @@ def fileslist(data, is_host=False, name_only=False, prefix=None):
prefix, prefix,
) )
for service, service_data in data.items(): for service, service_data in data.items():
if service_data['activate'] and service_data['engine'] != 'none': if not service_data['activate']:
_add(files, if service_data['engine'] == 'none' and service_data['type'] == 'service' and not 'overrides' in service_data:
{'owner': 'root', 'group': 'root', 'mode': '0755'},
base_systemd + '/systemd/system/' + service_data['doc'],
name_only,
prefix,
)
if service_data['activate'] and 'overrides' in service_data:
for override_data in service_data['overrides'].values():
_add(files, _add(files,
{'owner': 'root', 'group': 'root', 'mode': '0755'}, {'owner': 'root', 'group': 'root', 'mode': '0755'},
base_systemd + '/systemd/system/' + override_data['name'] + '.d/rougail.conf', base_systemd + '/systemd/system/' + service_data['doc'],
name_only, name_only,
prefix, prefix,
) )
else:
if service_data['activate'] and service_data['engine'] != 'none':
_add(files,
{'owner': 'root', 'group': 'root', 'mode': '0755'},
base_systemd + '/systemd/system/' + service_data['doc'],
name_only,
prefix,
)
if service_data['activate'] and 'overrides' in service_data:
for override_data in service_data['overrides'].values():
_add(files,
{'owner': 'root', 'group': 'root', 'mode': '0755'},
base_systemd + '/systemd/system/' + override_data['name'] + '.d/rougail.conf',
name_only,
prefix,
)
if 'files' not in service_data: if 'files' not in service_data:
continue continue
for file_data in service_data['files'].values(): for file_data in service_data['files'].values():

View file

@ -99,6 +99,7 @@ class RisottoInventory(object):
continue continue
ret[server_name] = engine.rougail_variables_dict ret[server_name] = engine.rougail_variables_dict
ret['modules'] = {module_name: module_info['infos'].depends for module_name, module_info in module_infos.items() if module_name in modules} ret['modules'] = {module_name: module_info['infos'].depends for module_name, module_info in module_infos.items() if module_name in modules}
ret['delete_old_image'] = False
ret['configure_host'] = True ret['configure_host'] = True
ret['only_machine'] = None ret['only_machine'] = None
return dumps(ret, cls=RougailEncoder) return dumps(ret, cls=RougailEncoder)

View file

@ -4,6 +4,7 @@ from time import sleep
from os import fdopen from os import fdopen
from dbus import SystemBus, Array from dbus import SystemBus, Array
from dbus.exceptions import DBusException from dbus.exceptions import DBusException
from subprocess import run
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
@ -141,6 +142,13 @@ def start(bus, machines):
errors.append(f'{host}: ' + '\n'.join(ret)) errors.append(f'{host}: ' + '\n'.join(ret))
return changed, errors return changed, errors
def enable(machines):
cmd = ['/usr/bin/machinectl', 'enable'] + machines
run(cmd)
return True
def run_module(): def run_module():
# define available arguments/parameters a user can pass to the module # define available arguments/parameters a user can pass to the module
module_args = dict( module_args = dict(
@ -172,21 +180,23 @@ def run_module():
if module.check_mode: if module.check_mode:
module.exit_json(**result) module.exit_json(**result)
bus = SystemBus()
# manipulate or modify the state as needed (this is going to be the # manipulate or modify the state as needed (this is going to be the
# part where your module will do what it needs to do) # part where your module will do what it needs to do)
machines = module.params['machines'] machines = module.params['machines']
if module.params['state'] == 'stopped': if module.params['state'] == 'stopped':
bus = SystemBus()
result['changed'], errors = stop(bus, machines) result['changed'], errors = stop(bus, machines)
if errors: if errors:
errors = '\n\n'.join(errors) errors = '\n\n'.join(errors)
module.fail_json(msg=f'Some machines are not stopping correctly {errors}', **result) module.fail_json(msg=f'Some machines are not stopping correctly {errors}', **result)
elif module.params['state'] == 'started': elif module.params['state'] == 'started':
bus = SystemBus()
result['changed'], errors = start(bus, machines) result['changed'], errors = start(bus, machines)
if errors: if errors:
errors = '\n\n'.join(errors) errors = '\n\n'.join(errors)
module.fail_json(msg=f'Some machines are not running correctly {errors}', **result) module.fail_json(msg=f'Some machines are not running correctly {errors}', **result)
elif module.params['state'] == 'enabled':
result['changed'] = enable(machines)
else: else:
module.fail_json(msg=f"Unknown state: {module.params['state']}") module.fail_json(msg=f"Unknown state: {module.params['state']}")

View file

@ -17,6 +17,7 @@
path: "installations{{ file.name }}" path: "installations{{ file.name }}"
checksum: sha256 checksum: sha256
get_checksum: yes get_checksum: yes
follow: true
loop: "{{ vars[item.name]['services'] | fileslist }}" loop: "{{ vars[item.name]['services'] | fileslist }}"
loop_control: loop_control:
loop_var: file loop_var: file
@ -28,6 +29,7 @@
path: "/var/lib/risotto/configurations/{{ item.name }}{{ file.name }}" path: "/var/lib/risotto/configurations/{{ item.name }}{{ file.name }}"
checksum: sha256 checksum: sha256
get_checksum: yes get_checksum: yes
follow: true
loop: "{{ vars[item.name]['services'] | fileslist }}" loop: "{{ vars[item.name]['services'] | fileslist }}"
loop_control: loop_control:
loop_var: file loop_var: file
@ -36,12 +38,12 @@
- name: "Configuration's file is up to date in {{ item.name }}" - name: "Configuration's file is up to date in {{ item.name }}"
debug: debug:
msg: "file is {{ 'out of date' if not file[1].stat.exists or file[0].stat.checksum != file[1].stat.checksum else 'up to date' }}" msg: "file is {{ 'out of date' if not file[1].stat.exists or (not 'checksum' in file[0].stat and 'checksum' in file[1].stat) or ('checksum' in file[0].stat and not 'checksum' in file[1].stat) or ('checksum' in file[0].stat and 'checksum' in file[1].stat and file[0].stat.checksum != file[1].stat.checksum) else 'up to date' }}"
changed_when: not file[1].stat.exists or file[0].stat.checksum != file[1].stat.checksum changed_when: not file[1].stat.exists or (not 'checksum' in file[0].stat and 'checksum' in file[1].stat) or ('checksum' in file[0].stat and not 'checksum' in file[1].stat) or ('checksum' in file[0].stat and 'checksum' in file[1].stat and file[0].stat.checksum != file[1].stat.checksum)
loop: "{{ local_configuration.results | zip(remote_configuration.results) | list }}" loop: "{{ local_configuration.results | zip(remote_configuration.results) | list }}"
loop_control: loop_control:
loop_var: file loop_var: file
label: "{{ file[0]['stat']['path'] }}" label: "{{ file[0]['file']['name'] }}"
ignore_errors: true ignore_errors: true
register: up_to_date_configuration register: up_to_date_configuration
@ -60,6 +62,24 @@
format: tar format: tar
when: up_to_date_configuration.changed when: up_to_date_configuration.changed
- name: "Remove old image {{ vars | modulename(item.name) }}"
file:
path: "/var/lib/risotto/images/{{ vars | modulename(item.name) }}.tar"
state: absent
when: delete_old_image == true
- name: "Stop machine {{ item.name }}"
machinectl:
state: stopped
machines: "{{ item.name }}"
when: delete_old_image == true
- name: "Remove old machine {{ item.name }}"
file:
path: /var/lib/machines/{{ item.name }}
state: absent
when: delete_old_image == true
- name: "Create system directory for {{ item.name }}" - name: "Create system directory for {{ item.name }}"
file: file:
path: /var/lib/machines/{{ item.name }} path: /var/lib/machines/{{ item.name }}
@ -69,6 +89,7 @@
- name: "Check image for {{ item.name }}" - name: "Check image for {{ item.name }}"
stat: stat:
path: "/var/lib/risotto/images/{{ vars | modulename(item.name) }}.tar" path: "/var/lib/risotto/images/{{ vars | modulename(item.name) }}.tar"
follow: true
register: register_name register: register_name
when: system_directory_created.changed when: system_directory_created.changed

View file

@ -21,6 +21,11 @@
dest: /var/lib/risotto/configurations/{{ item | basename }}/ dest: /var/lib/risotto/configurations/{{ item | basename }}/
loop: "{{ lookup('fileglob', '/tmp/new_configurations/*', wantlist=True) }}" loop: "{{ lookup('fileglob', '/tmp/new_configurations/*', wantlist=True) }}"
- name: "Enable machines"
machinectl:
state: enabled
machines: "{{ vars | machineslist(only_name=True) }}"
- name: "Start machines" - name: "Start machines"
machinectl: machinectl:
state: started state: started

View file

@ -131,6 +131,7 @@ fi
if [ -f "$IMAGE_NAME_RISOTTO_IMAGE_DIR".base.pkgs ] && [ -f "$IMAGE_NAME_RISOTTO_IMAGE_DIR".pkgs ]; then if [ -f "$IMAGE_NAME_RISOTTO_IMAGE_DIR".base.pkgs ] && [ -f "$IMAGE_NAME_RISOTTO_IMAGE_DIR".pkgs ]; then
echo " - différence(s) avec les paquets de base" echo " - différence(s) avec les paquets de base"
diff -u "$IMAGE_NAME_RISOTTO_IMAGE_DIR".base.pkgs "$BASE_PKGS_FILE" && INSTALL=false || INSTALL=true diff -u "$IMAGE_NAME_RISOTTO_IMAGE_DIR".base.pkgs "$BASE_PKGS_FILE" && INSTALL=false || INSTALL=true
[ ! -f "$IMAGE_NAME_RISOTTO_IMAGE_NAME" ] && INSTALL=true
else else
INSTALL=true INSTALL=true
fi fi

52
sbin/diagnose Normal file
View file

@ -0,0 +1,52 @@
#!/bin/bash -e
MACHINES=""
for nspawn in $(ls /etc/systemd/nspawn/*.nspawn); do
nspawn_file=$(basename $nspawn)
machine=${nspawn_file%.*}
MACHINES="$MACHINES$machine "
done
STARTED=""
DEGRADED=""
found=true
idx=0
while [ $found = true ]; do
found=false
echo "tentative $idx"
for machine in $MACHINES; do
if ! echo $STARTED | grep -q " $machine "; then
status=$(machinectl -q shell $machine /usr/bin/systemctl is-system-running 2>/dev/null || echo "not started")
if echo "$status" | grep -q degraded; then
STARTED="$STARTED $machine "
DEGRADED="$DEGRADED $machine"
elif echo "$status" | grep -q running; then
STARTED="$STARTED $machine "
else
found=true
echo "status actuel de $machine : $status"
fi
fi
done
sleep 2
idx=$((idx+1))
if [ $idx = 60 ]; then
break
fi
done
retcode=0
for machine in $MACHINES; do
if ! echo "$STARTED" | grep -q " $machine "; then
echo
echo "========= $machine"
machinectl -q shell $machine /usr/bin/systemctl is-system-running 2>/dev/null || echo "not started"
fi
done
echo $DEGRADED
for machine in $DEGRADED; do
echo
echo "========= $machine"
machinectl -q shell $machine /usr/bin/systemctl --state=failed --no-legend --no-pager
retcode=1
done
exit $retcode

View file

@ -15,7 +15,7 @@ ls /var/lib/risotto/images_files/ | while read image; do
/usr/local/sbin/build_image "$image" /usr/local/sbin/build_image "$image"
fi fi
done done
rm -f $IMAGE_BASE_RISOTTO_BASE_DIR*.build #rm -f $IMAGE_BASE_RISOTTO_BASE_DIR*.build
MACHINES="" MACHINES=""
for nspawn in $(ls /etc/systemd/nspawn/*.nspawn); do for nspawn in $(ls /etc/systemd/nspawn/*.nspawn); do
@ -23,11 +23,11 @@ for nspawn in $(ls /etc/systemd/nspawn/*.nspawn); do
machine=${nspawn_file%.*} machine=${nspawn_file%.*}
MACHINES="$MACHINES$machine " MACHINES="$MACHINES$machine "
MACHINE_MACHINES_DIR="/var/lib/machines/$machine" MACHINE_MACHINES_DIR="/var/lib/machines/$machine"
echo "Install machine $machine"
SHA_MACHINE="$RISOTTO_DIR/configurations/sha/$machine".sha SHA_MACHINE="$RISOTTO_DIR/configurations/sha/$machine".sha
content=$(cat $SHA_MACHINE) content=$(cat $SHA_MACHINE)
IMAGE_NAME_RISOTTO_IMAGE_NAME=${content##* } IMAGE_NAME_RISOTTO_IMAGE_NAME=${content##* }
diff -q "$IMAGE_NAME_RISOTTO_IMAGE_NAME".sha "$SHA_MACHINE" || ( diff -q "$IMAGE_NAME_RISOTTO_IMAGE_NAME".sha "$SHA_MACHINE" > /dev/null || (
echo "Reinstall machine $machine"
machinectl stop $machine machinectl stop $machine
while true; do while true; do
machinectl status "$machine" > /dev/null 2>&1 || break machinectl status "$machine" > /dev/null 2>&1 || break
@ -41,39 +41,4 @@ for nspawn in $(ls /etc/systemd/nspawn/*.nspawn); do
) )
done done
machinectl start $MACHINES machinectl start $MACHINES
STARTED="" diagnose
DEGRADED=""
found=true
idx=0
while [ $found = true ]; do
found=false
echo "tentative $idx"
for machine in $MACHINES; do
if ! echo $STARTED | grep -q " $machine "; then
status=$(machinectl -q shell $machine /usr/bin/systemctl is-system-running || true)
if echo "$status" | grep -q degraded; then
STARTED="$STARTED $machine "
DEGRADED="$DEGRADED $machine"
elif echo "$status" | grep -q running; then
STARTED="$STARTED $machine "
else
found=true
echo "status actuel de $machine : $status"
fi
fi
done
sleep 2
idx=$((idx+1))
if [ $idx = 60 ]; then
break
fi
done
retcode=0
for machine in $DEGRADED; do
echo
echo "========= $machine"
machinectl -q shell $machine /usr/bin/systemctl --state=failed --no-legend --no-pager
retcode=1
done
exit $retcode

View file

@ -163,8 +163,8 @@ def load_applicationservice(appname: str,
suppliers.setdefault(supplier, []) suppliers.setdefault(supplier, [])
if appname not in suppliers[supplier]: if appname not in suppliers[supplier]:
suppliers[supplier].append(appname) suppliers[supplier].append(appname)
if 'distribution' in app: if 'distribution' in app and app['distribution']:
distribution = app['distribution'] distribution = appname
else: else:
distribution = None distribution = None
for xml in app.get('depends', []): for xml in app.get('depends', []):
@ -181,7 +181,7 @@ def load_applicationservice(appname: str,
) )
if ret: if ret:
if distribution: if distribution:
raise Exception(f'duplicate distribution for {cfg.module_name} ({distribution} and {ret})') raise Exception(f'duplicate distribution for {cfg.module_name}: {distribution} and {ret} (dependencies: {cfg.depends}) ')
distribution = ret distribution = ret
return distribution return distribution
@ -209,7 +209,7 @@ def load_image_informations(module_name: str,
) )
if ret: if ret:
if distribution: if distribution:
raise Exception(f'duplicate distribution for {cfg.module_name} ({distribution} and {ret})') raise Exception(f'duplicate distribution for {cfg.module_name}: {distribution} and {ret} (dependencies: {cfg.depends}) ')
distribution = ret distribution = ret
if module_name != 'host' and not distribution: if module_name != 'host' and not distribution:
raise Exception(f'cannot found any linux distribution for {module_name}') raise Exception(f'cannot found any linux distribution for {module_name}')