diff --git a/playbooks/files/correct_mnt_state_permissions.py b/playbooks/files/correct_mnt_state_permissions.py new file mode 100755 index 0000000..eb67a7c --- /dev/null +++ b/playbooks/files/correct_mnt_state_permissions.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# 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 grp +import optparse +import os +import pwd +import stat + + +def get_object_ids(file): + stat_information = os.stat(file) + return(stat_information.st_uid, stat_information.st_gid) + + +def get_username_from_uid(old_uid, old_password_file): + file = open(old_password_file) + passwd_file = file.readlines() + for user_entry in passwd_file: + ( + user, + passwd, + uid, + gid, + gecos, + home, + shell + ) = user_entry.split(':') + if old_uid == int(uid): + return user + return "ErrUserNotFound" + + +def get_groupname_from_gid(old_gid, old_group_file): + file = open(old_group_file) + group_file = file.readlines() + for group_entry in group_file: + ( + group, + passwd, + gid, + members + ) = group_entry.split(':') + if old_gid == int(gid): + return group + return "ErrUserNotFound" + + +def get_new_uid(username): + return pwd.getpwnam(username).pw_uid + + +def get_new_gid(groupname): + return grp.getgrnam(groupname).gr_gid + + +def run_check(object, old_password_file, old_group_file): + (old_uid, old_gid) = get_object_ids(object) + old_username = get_username_from_uid(old_uid, old_password_file) + old_groupname = get_groupname_from_gid(old_uid, old_group_file) + try: + new_uid = get_new_uid(old_username) + new_gid = get_new_gid(old_groupname) + if old_uid != new_uid: + if old_username in object: + return(True, old_username, new_uid, old_groupname, new_gid) + return(False, old_username, new_uid, old_groupname, old_gid) + except: + return(False, old_username, -1, old_groupname, -1) + + +def recursive_update(directory, new_uid, new_gid): + os.chown(directory, new_uid, new_gid) + for root, dirs, files in os.walk(directory): + for dir in dirs: + os.chown(os.path.join(root, dir), new_uid, new_gid) + for file in files: + os.chown(os.path.join(root, file), new_uid, new_gid) + + +def main(): + usage = "Usage: %prog -f old_password_file -d directory_to_update" + parser = optparse.OptionParser(usage) + parser.add_option( + "-f", + action="store", + default=False, + dest="old_password_file", + help="Path to previous system password file" + ) + parser.add_option( + "-g", + action="store", + default=False, + dest="old_group_file", + help="Path to previous system password file" + ) + parser.add_option( + "-d", + action="store", + default=False, + dest="directory", + help="Directory to check and apply permission updates to" + ) + (options, args) = parser.parse_args() + + if not options.directory: + print("Error: please define a directory to run the program with -d") + parser.print_help() + return -1 + + if not options.old_password_file: + print("Error: please define a directory to run the program with -d") + parser.print_help() + return -1 + + if not options.old_group_file: + print("Error: please define a directory to run the program with -d") + parser.print_help() + return -1 + + + for object in os.listdir(options.directory): + if os.path.isdir(os.path.join(options.directory, object)): + (changed, old_user, new_uid, old_groupname, new_gid) = run_check( + os.path.join(options.directory, object), + options.old_password_file, + options.old_group_file + ) + if changed: + print("Updating %s/%s for ownership to uid %s for %s" % ( + options.directory, + object, + new_uid, + old_user + ) + ) + try: + recursive_update( + os.path.join(options.directory, object), + new_uid, + new_gid + ) + except: + print("Failed to update ownership of %s/%s " % ( + options.directory, + object + ) + ) + else: + print("ignoring %s/%s" % ( + options.directory, + object + ) + ) + else: + print("Ignoring %s/%s as it is not a directory" % ( + options.directory, + object + ) + ) + +main() diff --git a/playbooks/step_preserve_password_file.yml b/playbooks/step_preserve_password_file.yml new file mode 100644 index 0000000..a7228d3 --- /dev/null +++ b/playbooks/step_preserve_password_file.yml @@ -0,0 +1,23 @@ +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# 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. +- name: "Ensure /mnt/state/etc exists" + sudo: yes + file: path=/mnt/state/etc owner=root group=root mode=0755 state=directory +- name: "Saving a copy of /etc/passwd to /mnt/state/etc/passwd.backup" + sudo: yes + command: cp -a /etc/passwd /mnt/state/etc/passwd.backup +- name: "Saving a copy of /etc/group to /mnt/state/etc/passwd.backup" + sudo: yes + command: cp -a /etc/group /mnt/state/etc/group.backup diff --git a/playbooks/step_reset_mnt_state_permissions.yml b/playbooks/step_reset_mnt_state_permissions.yml new file mode 100644 index 0000000..44f3249 --- /dev/null +++ b/playbooks/step_reset_mnt_state_permissions.yml @@ -0,0 +1,21 @@ +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# 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. +- name: "Correcting Permissions for /mnt/state/var/log" + sudo: yes + script: files/correct_mnt_state_permissions.py -f /mnt/state/etc/passwd.backup -g /mnt/state/etc/group.backup -d /mnt/state/var/log +- name: "Correcting Permissions for /mnt/state/var/lib" + sudo: yes + script: files/correct_mnt_state_permissions.py -f /mnt/state/etc/passwd.backup -g /mnt/state/etc/group.backup -d /mnt/state/var/lib +- include: step_preserve_password_file.yml diff --git a/playbooks/update_cloud.yml b/playbooks/update_cloud.yml index 8e16be0..f09819c 100644 --- a/playbooks/update_cloud.yml +++ b/playbooks/update_cloud.yml @@ -167,6 +167,8 @@ gather_facts: no max_fail_percentage: 0 tasks: + - include: step_preserve_password_file.yml + when: instance_status == "ACTIVE" - include: preserve_ssh_host_keys.yml when: instance_status == "ACTIVE" - include: cleanup_cinder_volumes.yml @@ -202,6 +204,8 @@ gather_facts: no max_fail_percentage: 0 tasks: + - include: step_preserve_password_file.yml + when: instance_status == "ACTIVE" - include: preserve_ssh_host_keys.yml when: instance_status == "ACTIVE" - include: cleanup_cinder_volumes.yml @@ -231,6 +235,7 @@ file: path=/mnt/state/disable-os-collect-config state=absent - name: "Run os-collect-config" command: os-collect-config --force --one + - include: step_reset_mnt_state_permissions.yml - name: Bootstrap the MySQL cluster command: /etc/init.d/mysql bootstrap-pxc when: single_controller is not defined @@ -248,6 +253,8 @@ gather_facts: no max_fail_percentage: 0 tasks: + - include: step_preserve_password_file.yml + when: instance_status == "ACTIVE" - include: preserve_ssh_host_keys.yml when: instance_status == "ACTIVE" - include: cleanup_cinder_volumes.yml @@ -271,6 +278,7 @@ - include: mysql_init_fix.yml - include: stop_mysql.yml - include: rabbitmq_occ_disable.yml + - include: step_reset_mnt_state_permissions.yml - include: refresh_config.yml - name: Stop os-collect-config to avoid collission service: name=os-collect-config state=stopped @@ -399,6 +407,8 @@ gather_facts: no max_fail_percentage: 0 tasks: + - include: step_preserve_password_file.yml + when: instance_status == "ACTIVE" - include: preserve_ssh_host_keys.yml when: instance_status == "ACTIVE" - { include: rebuild.yml, instance_id: "{{ instance_id }}", rebuild_image_id: "{{ nova_compute_rebuild_image_id }}", when: instance_status != "REBUILD" }