def write_instance(instance_configuration): """Write a new or updated instance""" instance_name = instance_configuration["name"] instance_file = os.path.join( get_etc_instance_path(), instance_name + ".conf" ) instance_directory = os.path.join(get_etc_instance_path(), instance_name) try: log("Configuration:", instance_configuration, pretty=True, lvl=debug) with open(instance_file, "w") as f: f.write(dumps(instance_configuration)) log("Instance configuration stored.", lvl=debug) if not os.path.exists(instance_directory): os.mkdir(instance_directory) log("Instance configuration directory created.", lvl=debug) except PermissionError: log( "PermissionError: Could not write instance management configuration " "file or create instance configuration directory.", lvl=error, ) abort(EXIT_NO_PERMISSION)
def remove_instance(instance_configuration): """Remove the configuration file for an instance""" filename = os.path.join(get_etc_instance_path(), instance_configuration + ".conf") if os.path.exists(filename): log("Removing instance", instance_configuration) os.remove(filename) else: log("Instance not found.")
def load_instance(instance): """Read a single instance configuration""" file = os.path.join(get_etc_instance_path(), instance + ".conf") with open(file) as f: config = loads(f.read()) log("Instance configuration'", instance, "'loaded.", lvl=debug) return config
def load_instances(): """Read the instance configurations""" config = {} pattern = get_etc_instance_path() + "/*.conf" log("Loading all instance configuration files:", pattern, lvl=debug) for name in glob.glob(pattern): with open(name) as f: instance_name = os.path.basename(name).split(".")[0] config[instance_name] = loads(f.read()) log("Instance configuration '", instance_name, "'loaded.", lvl=debug) return config
def create_configuration(ctx): """Creates an initial configuration""" log("Creating new configuration from template", lvl=verbose) if not os.path.exists(get_etc_path()): try: os.makedirs(get_etc_path()) os.makedirs(get_etc_instance_path()) os.makedirs(get_etc_remote_path()) os.makedirs(get_etc_remote_keys_path()) except PermissionError: log( 'PermissionError: Could not create configuration directory "%s"' % get_etc_path(), lvl=warn, ) warn_error(EXIT_NO_PERMISSION) ctx.obj["config"] = configuration_template return ctx
def _instance_selfsigned(instance_configuration): """Generates a snakeoil certificate that has only been self signed""" log("Generating self signed certificate/key combination") try: os.mkdir("/etc/ssl/certs/isomer") except FileExistsError: pass except PermissionError: log("Need root (e.g. via sudo) to generate ssl certificate") abort(1) try: from OpenSSL import crypto except ImportError: log("Need python3-openssl to do this.") abort(1) return def create_self_signed_cert(target): """Create a simple self signed SSL certificate""" key_file = os.path.join(target, "selfsigned.key") cert_file = os.path.join(target, "selfsigned.crt") combined_file = os.path.join(target, "selfsigned.pem") web_section = instance_configuration['web'] cert_conf = { k: v for k, v in web_section.items() if k.startswith("certificate") } log("Certificate data:", cert_conf, pretty=True) hostname = instance_configuration.get("web", {}).get("hostnames", gethostname()) if isinstance(hostname, list): hostname = hostname[0] # create a key pair k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 2048) if os.path.exists(cert_file): try: certificate = open(cert_file, "rb").read() old_cert = crypto.load_certificate(crypto.FILETYPE_PEM, certificate) serial = old_cert.get_serial_number() + 1 except (crypto.Error, OSError) as e: log( "Could not read old certificate to increment serial:", type(e), e, exc=True, lvl=warn, ) serial = 1 else: serial = 1 # create a self-signed certificate certificate = crypto.X509() certificate.get_subject().C = cert_conf.get("certificate_country", "EU") certificate.get_subject().ST = cert_conf.get("certificate_state", "Sol") certificate.get_subject().L = cert_conf.get("certificate_location", "Earth") # noinspection PyPep8 certificate.get_subject().O = cert_conf.get("certificate_issuer", "Unknown") certificate.get_subject().OU = cert_conf.get("certificate_unit", "Unknown") certificate.get_subject().CN = hostname certificate.set_serial_number(serial) certificate.gmtime_adj_notBefore(0) certificate.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60) certificate.set_issuer(certificate.get_subject()) certificate.set_pubkey(k) certificate.sign(k, "sha512") open(key_file, "wt").write( str(crypto.dump_privatekey(crypto.FILETYPE_PEM, k), encoding="ASCII")) open(cert_file, "wt").write( str( crypto.dump_certificate(crypto.FILETYPE_PEM, certificate), encoding="ASCII", )) open(combined_file, "wt").write( str( crypto.dump_certificate(crypto.FILETYPE_PEM, certificate), encoding="ASCII", ) + str(crypto.dump_privatekey(crypto.FILETYPE_PEM, k), encoding="ASCII")) location = os.path.join(get_etc_instance_path(), instance_configuration.get("name")) create_self_signed_cert(location) instance_configuration["web"]["key"] = os.path.join( location, "selfsigned.key") instance_configuration["web"]["certificate"] = os.path.join( location, "selfsigned.crt") write_instance(instance_configuration)
def _archive(ctx, force=False, dynamic=False): instance_configuration = ctx.obj["instance_configuration"] next_environment = get_next_environment(ctx) env = instance_configuration["environments"][next_environment] log("Instance info:", instance_configuration, next_environment, pretty=True, lvl=debug) log("Installed:", env["installed"], "Tested:", env["tested"], lvl=debug) if (not env["installed"] or not env["tested"]) and not force: log("Environment has not been installed - not archiving.", lvl=warn) return False log("Archiving environment:", next_environment) set_instance(ctx.obj["instance"], next_environment) timestamp = std_now().replace(":", "-").replace(".", "-") temp_path = mkdtemp(prefix="isomer_backup") log("Archiving database") if not dump( instance_configuration["database_host"], instance_configuration["database_port"], env["database"], os.path.join(temp_path, "db_" + timestamp + ".json"), ): if not force: log("Could not archive database.") return False archive_filename = os.path.join( "/var/backups/isomer/", "%s_%s_%s.tgz" % (ctx.obj["instance"], next_environment, timestamp), ) try: shutil.copy( os.path.join(get_etc_instance_path(), ctx.obj["instance"] + ".conf"), temp_path, ) with tarfile.open(archive_filename, "w:gz") as f: if not dynamic: for item in locations: path = get_path(item, "") log("Archiving [%s]: %s" % (item, path)) f.add(path) f.add(temp_path, "db_etc") except (PermissionError, FileNotFoundError) as e: log("Could not archive environment:", e, lvl=error) if not force: return False finally: log("Clearing temporary backup target") shutil.rmtree(temp_path) ctx.obj["instance_configuration"]["environments"]["archive"][ timestamp] = env log(ctx.obj["instance_configuration"]) return archive_filename