class TelegrafIntegration(playbook_plugin.CephAnsiblePlaybook): NAME = "Telegraf Integration Plugin for Decapod" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.in_this_cluster CLUSTER_MUST_BE_DEPLOYED = True HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def make_playbook_configuration(self, cluster, servers, hints): global_vars = self.make_global_vars(cluster, servers, hints) inventory = self.make_inventory(cluster, servers, hints) return global_vars, inventory def make_global_vars(self, cluster, servers, hints): result = { "configpath": self.config["configpath"], "install": hints["install"], } result.update(self.config["settings"]) result.update(self.config["role"]) return result def make_inventory(self, cluster, servers, hints): hostvars = {} for srv in servers: hostvars.setdefault(srv.ip, {})["ansible_user"] = srv.username return {"telegraf": sorted(hostvars), "_meta": {"hostvars": hostvars}}
class AddMds(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add metadata server host" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["mdss"], task) def get_inventory_groups(self, cluster, servers, hints): base = super().get_inventory_groups(cluster, servers, hints) cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} mdss = [ cluster_servers[item["server_id"]] for item in cluster.configuration.state if item["role"] == "mdss" ] mdss_ips = {srv.ip for srv in mdss} for srv in servers: if srv.ip not in mdss_ips: mdss_ips.add(srv.ip) mdss.append(srv) base["mdss"] = mdss return base
class AddClient(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add RBD and CLI clients to the hosts" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["clients"], task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster data = cluster_data.ClusterData.find_one(cluster.model_id) data.global_vars = config["global_vars"] hostvars = config["inventory"].get("_meta", {}).get("hostvars", {}) for hostname, values in hostvars.items(): data.update_host_vars(hostname, values) data.save() def get_inventory_groups(self, cluster, servers, hints): base = super().get_inventory_groups(cluster, servers, hints) base["clients"] = servers return base
class AddNfs(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add NFS Gateway host" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["nfss", "rgws"], task) def make_global_vars(self, cluster, data, servers, hints): base = super().make_global_vars(cluster, data, servers, hints) base.update(nfs_file_gw=bool(hints["file_access"]), nfs_obj_gw=bool(hints["object_access"])) return base def get_inventory_groups(self, cluster, servers, hints): base = super().get_inventory_groups(cluster, servers, hints) rgws = servers if not hints["dont_deploy_rgw"] else [] base.update(rgws=rgws, nfss=servers) return base def prepare_plugin(self): resource_path = pathutils.resource("decapod_plugin_playbook_add_nfs", "roles") resource_path.symlink_to( str(playbook_plugin.PATH_CEPH_ANSIBLE.joinpath("roles")))
class PurgeTelegraf(playbook_plugin.CephAnsiblePlaybook): NAME = "Telegraf removal plugin for Decapod" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.any_server HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def make_playbook_configuration(self, cluster, servers, hints): global_vars = self.make_global_vars(cluster, servers, hints) inventory = self.make_inventory(cluster, servers, hints) return global_vars, inventory def make_global_vars(self, cluster, servers, hints): return { "remove_config_section_only": hints["remove_config_section_only"], "configpath": self.config["configpath"] } def make_inventory(self, cluster, servers, hints): hostvars = {} for srv in servers: hostvars.setdefault(srv.ip, {})["ansible_user"] = srv.username return {"telegraf": sorted(hostvars), "_meta": {"hostvars": hostvars}}
class RemoveClient(playbook_plugin.CephAnsiblePlaybookRemove): NAME = DESCRIPTION DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def get_dynamic_inventory(self): servers = {srv._id: srv for srv in self.playbook_config.servers} inventory = super().get_dynamic_inventory() hostvars = inventory["_meta"]["hostvars"] for data in self.playbook_config.cluster.configuration.state: if data["server_id"] in servers and data["role"] in BLOCKED_ROLES: srv = servers[data["server_id"]] hostvars[srv.ip]["blocked_by"] = data["role"] for values in hostvars.values(): values.setdefault("blocked_by", "") return inventory def on_post_execute(self, task, exc_value, exc_type, exc_tb): super().on_post_execute("clients", task, exc_value, exc_type, exc_tb) def make_global_vars(self, cluster, data, servers, hints): base = super().make_global_vars(cluster, data, servers, hints) base["uninstall_packages"] = bool(hints["uninstall_packages"]) base["apt_purge"] = bool(hints["apt_purge"]) return base def get_inventory_groups(self, cluster, servers, hints): return {"clients": servers}
class UpgradeCeph(playbook_plugin.CephAnsiblePlaybook): NAME = "Upgrade Ceph" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = False SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.in_this_cluster HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def make_playbook_configuration(self, cluster, servers, hints): global_vars = self.make_global_vars(cluster, servers, hints) inventory = self.make_inventory(cluster, servers, hints) return global_vars, inventory def make_global_vars(self, cluster, servers, hints): data = cluster_data.ClusterData.find_one(cluster.model_id) return { "do_timesync": hints["sync_time"], "ntp_server": self.config["ntp_server"], "mon": self.config["mon"], "osd": self.config["osd"], "cluster": data.global_vars["cluster"] } def make_inventory(self, cluster, servers, hints): radosgw_nodes, groups = self.get_inventory_groups( cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars["ansible_user"] = srv.username hostvars["has_radosgw"] = srv.ip in radosgw_nodes return inventory def get_inventory_groups(self, cluster, servers, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} inventory = {} for item in cluster.configuration.state: if item["role"] in ("mons", "clients", "osds"): inventory.setdefault(item["role"], []).append( cluster_servers[item["server_id"]]) radosgw_nodes = { cluster_servers[item["server_id"]].ip for item in cluster.configuration.state if item["role"] == "rgws"} return radosgw_nodes, inventory
class AddRestapi(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add Ceph REST API host" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["restapis"], task) def get_inventory_groups(self, cluster, servers, hints): base = super().get_inventory_groups(cluster, servers, hints) base["restapis"] = servers return base
class AddRgw(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add Rados Gateway to the cluster" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["rgws"], task) def get_inventory_groups(self, cluster, servers, hints): base = super().get_inventory_groups(cluster, servers, hints) base["rgws"] = servers return base
class RemoveNfs(playbook_plugin.CephAnsiblePlaybookRemove): NAME = "Remove NFS Gateway host" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_post_execute(self, task, exc_value, exc_type, exc_tb): playbook_plugin.CephAnsiblePlaybook.on_post_execute( task, exc_value, exc_type, exc_tb) if exc_value: LOG.warning("Cannot remove NFS gateway host: %s (%s)", exc_value, exc_type) raise exc_value playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster servers = playbook_config.servers servers = {srv.ip: srv for srv in servers} nfs_servers = config.pop("nfss") nfs_servers = [servers[ip] for ip in nfs_servers] cluster.remove_servers(nfs_servers, "nfss") rgw_servers = config.pop("rgws", []) if rgw_servers: rgw_servers = [servers[ip] for ip in rgw_servers] cluster.remove_servers(rgw_servers, "rgws") if cluster.configuration.changed: cluster.save() def make_global_vars(self, cluster, data, servers, hints): base = super().make_global_vars(cluster, data, servers, hints) base["ceph_nfs_rgw_user"] = data.global_vars["ceph_nfs_rgw_user"] base["remove_nfs_rgw_user"] = bool(hints["remove_nfs_rgw_user"]) return base def get_inventory_groups(self, cluster, servers, hints): groups = {"nfss": servers} if hints["remove_rgw"]: groups["rgws"] = servers return groups
class RemovePool(playbook_plugin.Playbook): NAME = "Remove Ceph pool" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = False SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.not_in_other_cluster HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def make_playbook_configuration(self, cluster, servers, hints): data = cluster_data.ClusterData.find_one(cluster.model_id) global_vars = self.make_global_vars(cluster, data, hints) inventory = self.make_inventory(cluster, hints) return global_vars, inventory def make_global_vars(self, cluster, data, hints): return { "pool_names": [hints["pool_name"]], "cluster": data.global_vars.get("cluster", cluster.name) } def make_inventory(self, cluster, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} mons = [ cluster_servers[item["server_id"]] for item in cluster.configuration.state if item["role"] == "mons" ] return { "mons": [mons[0].ip], "_meta": { "hostvars": { mons[0].ip: { "ansible_user": mons[0].username } } } }
class RestartServices(playbook_plugin.Playbook): NAME = "Restart services" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.in_this_cluster HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def make_playbook_configuration(self, cluster, servers, hints): global_vars = self.make_global_vars(cluster, servers, hints) inventory = self.make_inventory(cluster, servers, hints) return global_vars, inventory def make_global_vars(self, cluster, servers, hints): data = cluster_data.ClusterData.find_one(cluster.model_id) return { "mon": self.config["mon"], "osd": self.config["osd"], "radosgw": self.config["radosgw"], "restapi": self.config["restapi"], "cluster": data.global_vars["cluster"] } def make_inventory(self, cluster, servers, hints): groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars["ansible_user"] = srv.username return inventory def get_inventory_groups(self, cluster, servers, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} allowed_groups = set() if hints["restart_osd"]: allowed_groups.add("osds") if hints["restart_mon"]: allowed_groups.add("mons") if hints["restart_rgw"]: allowed_groups.add("rgws") if hints["restart_restapi"]: allowed_groups.add("restapis") allowed_servers = {srv._id for srv in servers} inventory = {} for item in cluster.configuration.state: if item["role"] in allowed_groups and item[ "server_id"] in allowed_servers: # NOQA inventory.setdefault(item["role"], []).append( cluster_servers[item["server_id"]]) return inventory
} """Schema for playbook hints.""" LOG = log.getLogger(__name__) """Logger.""" class {{ cookiecutter.plugin_class_name }}(playbook_plugin.CephAnsiblePlaybook): NAME = "{{ cookiecutter.plugin_display_name }}" DESCRIPTION = DESCRIPTION PUBLIC = {{ cookiecutter.is_public }} REQUIRED_SERVER_LIST = {{ cookiecutter.required_server_list }} SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.not_in_other_cluster HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster servers = playbook_config.servers servers = {srv.ip: srv for srv in servers} def on_post_execute(self, task, exc_value, exc_type, exc_tb): super().on_post_execute(task, exc_value, exc_type, exc_tb) if exc_value: raise exc_value
class AddOSD(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add OSD to Ceph cluster" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["osds"], task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster data = cluster_data.ClusterData.find_one(cluster.model_id) hostvars = config.get("_meta", {}).get("hostvars", {}) for hostname, values in hostvars.items(): data.update_host_vars(hostname, values) data.save() def make_global_vars(self, cluster, data, servers, hints): base = super().make_global_vars(cluster, data, servers, hints) base["journal_collocation"] = False base["dmcrypt_journal_collocation"] = False base["dmcrypt_dedicated_journal"] = False base["raw_multi_journal"] = False if hints["dmcrypt"]: if hints["collocation"]: base["dmcrypt_journal_collocation"] = True else: base["dmcrypt_dedicated_journal"] = True elif hints["collocation"]: base["journal_collocation"] = True else: base["raw_multi_journal"] = True return base def make_inventory(self, cluster, data, servers, hints): global_vars = self.make_global_vars(cluster, data, servers, hints) groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} all_servers = server.ServerModel.cluster_servers(cluster.model_id) for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars.update(data.get_host_vars(srv.ip)) if "ansible_user" not in hostvars: hostvars["ansible_user"] = srv.username if "monitor_interface" not in hostvars: if "monitor_address" not in hostvars: hostvars["monitor_address"] = \ networkutils.get_public_network_ip( srv, all_servers) if hints["collocation"]: hostvars["devices"] = diskutils.get_devices(srv) else: hostvars["devices"] = [] hostvars["raw_journal_devices"] = [] for pair in diskutils.get_data_journal_pairs_iter( srv, int(global_vars["journal_size"])): hostvars["devices"].append(pair["data"]) hostvars["raw_journal_devices"].append(pair["journal"]) return inventory def get_inventory_groups(self, cluster, servers, hints): base = super().get_inventory_groups(cluster, servers, hints) base["osds"] = servers return base def prepare_plugin(self): resource_path = pathutils.resource( "decapod_plugin_playbook_add_osd", "roles") resource_path.symlink_to( str(playbook_plugin.PATH_CEPH_ANSIBLE.joinpath("roles")))
class DeployCluster(playbook_plugin.CephAnsiblePlaybook): NAME = "Deploy Ceph cluster" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.not_in_any_cluster CLUSTER_MUST_BE_DEPLOYED = False HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration cluster = playbook_config.cluster servers = playbook_config.servers servers = {srv.ip: srv for srv in servers} for name, group_vars in config["inventory"].items(): if name == "_meta" or not group_vars: continue group_servers = [servers[ip] for ip in group_vars] cluster.add_servers(group_servers, name) if cluster.configuration.changed: cluster.save() # Save persistent cluster data. We will override existing settings # because cluster is created from scratch using this plugin. global_vars = config["global_vars"].copy() global_vars.pop("ceph_facts_template", None) global_vars.pop("restapi_template_local_path", None) data = cluster_data.ClusterData.find_one(cluster.model_id) data.global_vars = global_vars data.host_vars = config["inventory"].get("_meta", {}).get("hostvars", {}) data.save() def make_playbook_configuration(self, cluster, servers, hints): if cluster.configuration.state or cluster.server_list: raise exceptions.NotEmptyServerList(cluster.model_id) global_vars = self.make_global_vars(cluster, servers, hints) inventory = self.make_inventory(cluster, servers, hints, global_vars) if not monitor_secret.MonitorSecret.find_one(cluster.model_id): monitor_secret.MonitorSecret.upsert( cluster.model_id, monitor_secret.generate_monitor_secret()) return global_vars, inventory def get_dynamic_inventory(self): # we need to inject monitor_secret here to avoid # showing it in interface if not self.playbook_config: raise exceptions.UnknownPlaybookConfiguration() configuration = self.playbook_config.configuration inventory = configuration["inventory"] secret = monitor_secret.MonitorSecret.find_one( configuration["global_vars"]["fsid"]) if not secret: raise exceptions.SecretWasNotFound( configuration["global_vars"]["fsid"]) all_hosts = set() for name, group_vars in inventory.items(): if name == "_meta": continue all_hosts.update(group_vars) for hostname in all_hosts: dct = inventory["_meta"]["hostvars"].setdefault(hostname, {}) dct["monitor_secret"] = secret.value return inventory def make_global_vars(self, cluster, servers, hints): result = super().make_global_vars(cluster, servers, hints) result["journal_collocation"] = False result["dmcrypt_journal_collocation"] = False result["dmcrypt_dedicated_journal"] = False result["raw_multi_journal"] = False if hints["dmcrypt"]: if hints["collocation"]: result["dmcrypt_journal_collocation"] = True else: result["dmcrypt_dedicated_journal"] = True elif hints["collocation"]: result["journal_collocation"] = True else: result["raw_multi_journal"] = True result["restapi_template_local_path"] = str( pathutils.resource("decapod_plugin_playbook_deploy_cluster", "ceph-rest-api.service")) return result def make_inventory(self, cluster, servers, hints, global_vars): groups = self.get_inventory_groups(servers, hints) inventory = {"_meta": {"hostvars": {}}} for name, group_servers in groups.items(): inventory[name] = [srv.ip for srv in group_servers] for srv in servers: hostvars = inventory["_meta"]["hostvars"].setdefault(srv.ip, {}) hostvars["ansible_user"] = srv.username hostvars["monitor_address"] = networkutils.get_public_network_ip( srv, servers) if hints["collocation"]: hostvars["devices"] = diskutils.get_devices(srv) else: hostvars["devices"] = [] hostvars["raw_journal_devices"] = [] for pair in diskutils.get_data_journal_pairs_iter( srv, int(global_vars["journal_size"])): hostvars["devices"].append(pair["data"]) hostvars["raw_journal_devices"].append(pair["journal"]) return inventory def get_inventory_groups(self, servers, hints): servers = sorted(servers, key=diskutils.get_server_storage_size) mons = servers[:hints["mon_count"]] osds = servers[hints["mon_count"]:] result = { "mons": mons, "osds": osds, "rgws": [], "mdss": [], "nfss": [], "rbdmirrors": [], "clients": [], "iscsi_gw": [], "restapis": [] } if hints["rest_api"]: result["restapis"] = result["mons"] return result def prepare_plugin(self): resource_path = pathutils.resource( "decapod_plugin_playbook_deploy_cluster", "roles") resource_path.symlink_to( str(playbook_plugin.PATH_CEPH_ANSIBLE.joinpath("roles")))
class AddOSD(playbook_plugin.CephAnsiblePlaybook): NAME = "Add OSD to Ceph cluster" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.not_in_other_cluster HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster servers = playbook_config.servers servers = {srv.ip: srv for srv in servers} for name, group_vars in config.items(): if name == "_meta" or not group_vars: continue group_servers = [servers[ip] for ip in group_vars] cluster.add_servers(group_servers, name) if cluster.configuration.changed: cluster.save() data = cluster_data.ClusterData.find_one(cluster.model_id) hostvars = config.get("_meta", {}).get("hostvars", {}) for hostname, values in hostvars.items(): data.update_host_vars(hostname, values) data.save() def make_playbook_configuration(self, cluster, servers, hints): cluster_config = cluster.configuration.make_api_structure() if not cluster_config.get("mons"): raise exceptions.NoMonitorsError(cluster.model_id) data = cluster_data.ClusterData.find_one(cluster.model_id) global_vars = self.make_global_vars(cluster, data, servers, hints) inventory = self.make_inventory(cluster, data, servers, hints, global_vars) return global_vars, inventory def make_global_vars(self, cluster, data, servers, hints): result = super().make_global_vars(cluster, servers, hints) result.update(data.global_vars) result["journal_collocation"] = False result["dmcrypt_journal_collocation"] = False result["dmcrypt_dedicated_journal"] = False result["raw_multi_journal"] = False result["ceph_version_verify"] = bool(hints["ceph_version_verify"]) result["ceph_version_verify_packagename"] = \ self.config["ceph_version_verify_packagename"] if hints["dmcrypt"]: if hints["collocation"]: result["dmcrypt_journal_collocation"] = True else: result["dmcrypt_dedicated_journal"] = True elif hints["collocation"]: result["journal_collocation"] = True else: result["raw_multi_journal"] = True if "journal_size" not in result: result["journal_size"] = self.config["journal"]["size"] result["ceph_facts_template"] = pathutils.resource( "decapod_common", "facts", "ceph_facts_module.py.j2") result["ceph_facts_template"] = str(result["ceph_facts_template"]) return result def make_inventory(self, cluster, data, servers, hints, global_vars): groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} all_servers = server.ServerModel.cluster_servers(cluster.model_id) for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars.update(data.get_host_vars(srv.ip)) if "ansible_user" not in hostvars: hostvars["ansible_user"] = srv.username if "monitor_interface" not in hostvars: hostvars["monitor_interface"] = \ networkutils.get_public_network_if(srv, all_servers) if hints["collocation"]: hostvars["devices"] = diskutils.get_devices(srv) else: hostvars["devices"] = [] hostvars["raw_journal_devices"] = [] for pair in diskutils.get_data_journal_pairs_iter( srv, int(global_vars["journal_size"])): hostvars["devices"].append(pair["data"]) hostvars["raw_journal_devices"].append(pair["journal"]) return inventory def get_inventory_groups(self, cluster, servers, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} mons = [ cluster_servers[item["server_id"]] for item in cluster.configuration.state if item["role"] == "mons" ] return { "mons": mons, "osds": servers, "already_deployed": list(cluster_servers.values()) } def prepare_plugin(self): resource_path = pathutils.resource("decapod_plugin_playbook_add_osd", "roles") resource_path.symlink_to( str(playbook_plugin.PATH_CEPH_ANSIBLE.joinpath("roles")))
class AddMon(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add monitor to the cluster" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["mons"], task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster data = cluster_data.ClusterData.find_one(cluster.model_id) hostvars = config.get("_meta", {}).get("hostvars", {}) for hostname, values in hostvars.items(): data.update_host_vars(hostname, values) data.save() def get_dynamic_inventory(self): if not self.playbook_config: raise exceptions.UnknownPlaybookConfiguration() configuration = self.playbook_config.configuration inventory = configuration["inventory"] secret = get_monitor_secret(configuration["global_vars"]["fsid"]) if not secret: raise exceptions.SecretWasNotFound( configuration["global_vars"]["fsid"]) all_hosts = set() for name, group_vars in inventory.items(): if name == "_meta": continue all_hosts.update(group_vars) for hostname in all_hosts: dct = inventory["_meta"]["hostvars"].setdefault(hostname, {}) dct["monitor_secret"] = secret.value return inventory def make_inventory(self, cluster, data, servers, hints): groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} all_servers = server.ServerModel.cluster_servers(cluster.model_id) for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars.update(data.get_host_vars(srv.ip)) if "ansible_user" not in hostvars: hostvars["ansible_user"] = srv.username if "monitor_interface" not in hostvars: if "monitor_address" not in hostvars: hostvars["monitor_address"] = \ networkutils.get_public_network_ip( srv, all_servers) return inventory def get_inventory_groups(self, cluster, servers, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} old_mons = [ cluster_servers[item["server_id"]] for item in cluster.configuration.state if item["role"] == "mons" ] mons = {srv.model_id: srv for srv in old_mons} mons.update((srv.model_id, srv) for srv in servers) return { "oldmons": old_mons, "mons": sorted(mons.values(), key=lambda srv: srv.ip), "already_deployed": list(cluster_servers.values()) } def prepare_plugin(self): resource_path = pathutils.resource("decapod_plugin_playbook_add_mon", "roles") resource_path.symlink_to( str(playbook_plugin.PATH_CEPH_ANSIBLE.joinpath("roles")))
class AddMon(playbook_plugin.CephAnsiblePlaybook): NAME = "Add monitor to the cluster" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.not_in_other_cluster HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster servers = playbook_config.servers servers = {srv.ip: srv for srv in servers} for name, group_vars in config.items(): if name == "_meta" or not group_vars: continue group_servers = [servers[ip] for ip in group_vars] cluster.add_servers(group_servers, name) if cluster.configuration.changed: cluster.save() data = cluster_data.ClusterData.find_one(cluster.model_id) hostvars = config.get("_meta", {}).get("hostvars", {}) for hostname, values in hostvars.items(): data.update_host_vars(hostname, values) data.save() def make_playbook_configuration(self, cluster, servers, hints): data = cluster_data.ClusterData.find_one(cluster.model_id) global_vars = self.make_global_vars(cluster, data, servers, hints) inventory = self.make_inventory(cluster, data, servers, hints) return global_vars, inventory def make_global_vars(self, cluster, data, servers, hints): result = super().make_global_vars(cluster, servers, hints) result.update(data.global_vars) result["ceph_version_verify"] = bool(hints["ceph_version_verify"]) result["ceph_version_verify_packagename"] = \ self.config["ceph_version_verify_packagename"] result["ceph_facts_template"] = pathutils.resource( "decapod_common", "facts", "ceph_facts_module.py.j2") result["ceph_facts_template"] = str(result["ceph_facts_template"]) return result def get_dynamic_inventory(self): if not self.playbook_config: raise exceptions.UnknownPlaybookConfiguration() configuration = self.playbook_config.configuration inventory = configuration["inventory"] secret = get_monitor_secret(configuration["global_vars"]["fsid"]) if not secret: raise exceptions.SecretWasNotFound( configuration["global_vars"]["fsid"]) all_hosts = set() for name, group_vars in inventory.items(): if name == "_meta": continue all_hosts.update(group_vars) for hostname in all_hosts: dct = inventory["_meta"]["hostvars"].setdefault(hostname, {}) dct["monitor_secret"] = secret.value return inventory def make_inventory(self, cluster, data, servers, hints): groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars.update(data.get_host_vars(srv.ip)) if "ansible_user" not in hostvars: hostvars["ansible_user"] = srv.username if "monitor_interface" not in hostvars: hostvars["monitor_interface"] = \ networkutils.get_public_network_if(srv, servers) return inventory def get_inventory_groups(self, cluster, servers, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} mons = [ cluster_servers[item["server_id"]] for item in cluster.configuration.state if item["role"] == "mons" ] mons = {srv.model_id: srv for srv in mons} mons.update((srv.model_id, srv) for srv in servers) return { "mons": sorted(mons.values(), key=lambda srv: srv.ip), "already_deployed": list(cluster_servers.values()) } def prepare_plugin(self): resource_path = pathutils.resource("decapod_plugin_playbook_add_mon", "roles") resource_path.symlink_to( str(playbook_plugin.PATH_CEPH_ANSIBLE.joinpath("roles")))
class AddOSD(playbook_plugin.CephAnsiblePlaybook): NAME = "Add OSD to Ceph cluster" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster servers = playbook_config.servers servers = {srv.ip: srv for srv in servers} for name, group_vars in config.items(): if name == "_meta" or not group_vars: continue group_servers = [servers[ip] for ip in group_vars] cluster.add_servers(group_servers, name) if cluster.configuration.changed: cluster.save() def make_playbook_configuration(self, cluster, servers, hints): cluster_config = cluster.configuration.make_api_structure() if not cluster_config.get("mons"): raise exceptions.NoMonitorsError(cluster.model_id) global_vars = self.make_global_vars(cluster, servers, hints) inventory = self.make_inventory(cluster, servers, hints) return global_vars, inventory def make_global_vars(self, cluster, servers, hints): result = super().make_global_vars(cluster, servers, hints) result["journal_collocation"] = False result["dmcrypt_journal_collocation"] = False result["dmcrypt_dedicated_journal"] = False result["raw_multi_journal"] = False if hints["dmcrypt"]: if hints["collocation"]: result["dmcrypt_journal_collocation"] = True else: result["dmcrypt_dedicated_journal"] = True elif hints["collocation"]: result["journal_collocation"] = True else: result["raw_multi_journal"] = True result["journal_size"] = self.config["journal"]["size"] result["ceph_facts_template"] = pkg_resources.resource_filename( "decapod_common", "facts/ceph_facts_module.py.j2") return result def make_inventory(self, cluster, servers, hints): groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} all_servers = server.ServerModel.cluster_servers(cluster.model_id) for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars["ansible_user"] = srv.username hostvars["monitor_interface"] = networkutils.get_public_network_if( # NOQA srv, all_servers) if hints["collocation"]: hostvars["devices"] = diskutils.get_devices(srv) else: hostvars["devices"] = [] hostvars["raw_journal_devices"] = [] for pair in diskutils.get_data_journal_pairs_iter(srv): hostvars["devices"].append(pair["data"]) hostvars["raw_journal_devices"].append(pair["journal"]) return inventory def get_inventory_groups(self, cluster, servers, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} mons = [ cluster_servers[item["server_id"]] for item in cluster.configuration.state if item["role"] == "mons" ] return {"mons": mons, "osds": servers}
class DeployCluster(playbook_plugin.CephAnsiblePlaybook): NAME = "Deploy Ceph cluster" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = True HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster servers = playbook_config.servers servers = {srv.ip: srv for srv in servers} for name, group_vars in config.items(): if name == "_meta" or not group_vars: continue group_servers = [servers[ip] for ip in group_vars] cluster.add_servers(group_servers, name) if cluster.configuration.changed: cluster.save() def make_playbook_configuration(self, cluster, servers, hints): if cluster.configuration.state or cluster.server_list: raise exceptions.NotEmptyServerList(cluster.model_id) global_vars = self.make_global_vars(cluster, servers, hints) inventory = self.make_inventory(cluster, servers, hints) if not monitor_secret.MonitorSecret.find_one(cluster.model_id): monitor_secret.MonitorSecret.upsert( cluster.model_id, monitor_secret.generate_monitor_secret()) return global_vars, inventory def get_dynamic_inventory(self): # we need to inject monitor_secret here to avoid # showing it in interface if not self.playbook_config: raise exceptions.UnknownPlaybookConfiguration() configuration = self.playbook_config.configuration inventory = configuration["inventory"] secret = monitor_secret.MonitorSecret.find_one( configuration["global_vars"]["fsid"]) if not secret: raise exceptions.SecretWasNotFound( configuration["global_vars"]["fsid"]) all_hosts = set() for name, group_vars in inventory.items(): if name == "_meta": continue all_hosts.update(group_vars) for hostname in all_hosts: dct = inventory["_meta"]["hostvars"].setdefault(hostname, {}) dct["monitor_secret"] = secret.value return inventory def make_global_vars(self, cluster, servers, hints): result = super().make_global_vars(cluster, servers, hints) result["journal_collocation"] = False result["dmcrypt_journal_collocation"] = False result["dmcrypt_dedicated_journal"] = False result["raw_multi_journal"] = False if hints["dmcrypt"]: if hints["collocation"]: result["dmcrypt_journal_collocation"] = True else: result["dmcrypt_dedicated_journal"] = True elif hints["collocation"]: result["journal_collocation"] = True else: result["raw_multi_journal"] = True result["journal_size"] = self.config["journal"]["size"] result["ceph_facts_template"] = pkg_resources.resource_filename( "decapod_common", "facts/ceph_facts_module.py.j2") result["restapi_template_local_path"] = \ pkg_resources.resource_filename( "decapod_plugin_playbook_deploy_cluster", "ceph-rest-api.service") return result def make_inventory(self, cluster, servers, hints): groups = self.get_inventory_groups(servers, hints) inventory = {"_meta": {"hostvars": {}}} for name, group_servers in groups.items(): inventory[name] = [srv.ip for srv in group_servers] for srv in servers: hostvars = inventory["_meta"]["hostvars"].setdefault(srv.ip, {}) hostvars["ansible_user"] = srv.username hostvars["monitor_interface"] = networkutils.get_public_network_if( srv, servers) if hints["collocation"]: hostvars["devices"] = diskutils.get_devices(srv) else: hostvars["devices"] = [] hostvars["raw_journal_devices"] = [] for pair in diskutils.get_data_journal_pairs_iter(srv): hostvars["devices"].append(pair["data"]) hostvars["raw_journal_devices"].append(pair["journal"]) return inventory def get_inventory_groups(self, servers, hints): servers = sorted(servers, key=diskutils.get_server_storage_size) mons = servers[:hints["mon_count"]] osds = servers[hints["mon_count"]:] result = { "mons": mons, "osds": osds, "rgws": [], "mdss": [], "nfss": [], "rbd_mirrors": [], "clients": [], "iscsi_gw": [], "restapis": [] } if hints["rest_api"]: result["restapis"] = result["mons"] return result
class AddRbdmirror(playbook_plugin.CephAnsibleNewWithVerification): NAME = "Add RBD Mirroring host" DESCRIPTION = DESCRIPTION HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_pre_execute(self, task): super().on_pre_execute(["rbdmirrors"], task) playbook_config = self.get_playbook_configuration(task) config = playbook_config.configuration["inventory"] cluster = playbook_config.cluster data = cluster_data.ClusterData.find_one(cluster.model_id) hostvars = config.get("_meta", {}).get("hostvars", {}) for hostname, values in hostvars.items(): data.update_host_vars(hostname, values) data.save() def get_dynamic_inventory(self): inventory = super().get_dynamic_inventory() hostvars = inventory["_meta"]["hostvars"] for data in hostvars.values(): data["ceph_rbd_mirror_configure"] = False if "rbd_mirrors" not in data: continue reworked = {} for usercluster, pools in data["rbd_mirrors"].items(): user, cluster = usercluster.split("@") pool_list = reworked.setdefault(user, {}) for pool in pools: pool_list.setdefault(cluster, []).append(pool) data["rbd_mirrors"] = reworked return inventory def get_extra_vars(self, task): extra_vars = super().get_extra_vars(task) extra_vars.pop("ceph_rbd_mirror_configure", None) extra_vars.setdefault("ceph_rbd_mirror_local_user", "admin") return extra_vars def make_global_vars(self, cluster, data, servers, hints): base = super().make_global_vars(cluster, data, servers, hints) base["add_peers"] = bool(hints["add_peers"]) return base def make_inventory(self, cluster, data, servers, hints): groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars.update(data.get_host_vars(srv.ip)) hostvars["ansible_user"] = srv.username if name == "rbdmirrors": self.update_hostvars(hostvars, srv, hints) return inventory def get_inventory_groups(self, cluster, servers, hints): base = super().get_inventory_groups(cluster, servers, hints) base["rbdmirrors"] = servers return base def update_hostvars(self, hostvars, srv, hints): pools = hostvars.setdefault("rbd_mirrors", {}) mirror_for = "{0}@{1}".format( hints["remote_username"], hints["remote_clustername"]) pool_list = set(pools.get(mirror_for, [])) pool_list.add(hints["poolname"]) pools[mirror_for] = sorted(pool_list) hostvars["rbd_mirrors"] = pools
class CinderIntegration(playbook_plugin.CephAnsiblePlaybook): NAME = "Cinder Integration" DESCRIPTION = DESCRIPTION PUBLIC = True REQUIRED_SERVER_LIST = False SERVER_LIST_POLICY = playbook_plugin.ServerListPolicy.in_this_cluster HINTS = playbook_plugin_hints.Hints(HINTS_SCHEMA) def on_post_execute(self, task, exc_value, exc_type, exc_tb): try: if exc_value: raise exc_value configuration = self.get_playbook_configuration(task) cint = cinder_integration.CinderIntegration.find_one( configuration.cluster_id) cint.keyrings.clear() cint.config = self.fetchdir.joinpath("ceph.conf").read_text() for filename in self.fetchdir.glob("*.keyring"): cint.keyrings[filename.name] = filename.read_text() cint.save() finally: super().on_post_execute(task, exc_value, exc_type, exc_tb) def make_playbook_configuration(self, cluster, servers, hints): data = cluster_data.ClusterData.find_one(cluster.model_id) global_vars = self.make_global_vars(cluster, data, servers, hints) inventory = self.make_inventory(cluster, data, servers, hints) return global_vars, inventory def make_global_vars(self, cluster, data, servers, hints): return { "cluster": data.global_vars.get("cluster", cluster.name) } def make_inventory(self, cluster, data, servers, hints): groups = self.get_inventory_groups(cluster, servers, hints) inventory = {"_meta": {"hostvars": {}}} config = self.config.copy() for config_key in "pools", "clients": if not hints["glance"]: config[config_key].pop("images", None) if not hints["nova"]: config[config_key].pop("compute", None) if not hints["cinder"]: config[config_key].pop("volumes", None) for name, group_servers in groups.items(): for srv in group_servers: inventory.setdefault(name, []).append(srv.ip) hostvars = inventory["_meta"]["hostvars"].setdefault( srv.ip, {}) hostvars["ansible_user"] = srv.username hostvars.update(config) return inventory def get_inventory_groups(self, cluster, servers, hints): cluster_servers = server.ServerModel.cluster_servers(cluster.model_id) cluster_servers = {item._id: item for item in cluster_servers} mons = [ cluster_servers[item["server_id"]] for item in cluster.configuration.state if item["role"] == "mons" ] return {"mons": [mons[0]]}