/* * Copyright (C) 2020-2021 Soleta Networks * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the * Free Software Foundation; either version 3 of the License, or * (at your option) any later version. */ #include #include #include #include #include "dbi.h" #include "cfg.h" #include #include #include #define OG_SCHEMA_STMTS_V2 7 static const char *stmts_v2[OG_SCHEMA_STMTS_V2] = { [0] = "ALTER TABLE `aulas` " "ADD CONSTRAINT FK_centros " "FOREIGN KEY (`idcentro`) " "REFERENCES `centros` (`idcentro`) ON DELETE CASCADE", [1] = "ALTER TABLE `ordenadores` " "ADD CONSTRAINT FK_aulas " "FOREIGN KEY (`idaula`) " "REFERENCES `aulas` (`idaula`) ON DELETE CASCADE", [2] = "ALTER TABLE `ordenadores_particiones` " "ADD CONSTRAINT FK_ordenadores " "FOREIGN KEY (`idordenador`) " "REFERENCES `ordenadores` (`idordenador`) ON DELETE CASCADE", [3] = "DELETE PS FROM perfilessoft_softwares AS PS " "WHERE NOT EXISTS (" "SELECT null FROM softwares AS S " "WHERE S.idsoftware = PS.idsoftware)", [4] = "ALTER TABLE `perfilessoft_softwares` " "ADD CONSTRAINT FK_softwares " "FOREIGN KEY (`idsoftware`) " "REFERENCES `softwares` (`idsoftware`) ON DELETE CASCADE", [5] = "ALTER TABLE `perfilessoft_softwares` " "ADD CONSTRAINT FK_perfilessoft " "FOREIGN KEY (`idperfilsoft`) " "REFERENCES `perfilessoft` (`idperfilsoft`) ON DELETE CASCADE", [6] = "UPDATE version SET version = 2", }; static int og_dbi_create_version(struct og_dbi *dbi) { const char *msglog; dbi_result result; result = dbi_conn_queryf(dbi->conn, "CREATE TABLE `version` " "(`version` smallint unsigned NOT NULL) " "ENGINE='MyISAM' COLLATE 'utf8_general_ci'"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not create schema version table (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_queryf(dbi->conn, "INSERT INTO `version` (`version`) VALUES ('0')"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not insert into schema version table (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_version(struct og_dbi *dbi) { const char *msglog; dbi_result result; uint32_t version; result = dbi_conn_queryf(dbi->conn, "SELECT * from version"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "no version table found (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } if (!dbi_result_last_row(result)) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "cannot get last row from version table (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } version = dbi_result_get_uint(result, "version"); dbi_result_free(result); return version; } static int og_dbi_schema_v1(struct og_dbi *dbi) { const char *msglog, *command; dbi_result result, result_alter; result = dbi_conn_queryf(dbi->conn, "SELECT concat('alter table `',TABLE_SCHEMA,'`.`',TABLE_NAME,'` engine=innodb;')" "AS cmd FROM information_schema.TABLES WHERE TABLE_SCHEMA='%s'", ogconfig.db.name); while (dbi_result_next_row(result)) { command = dbi_result_get_string(result, "cmd"); syslog(LOG_DEBUG, "Upgrading to innoDB: %s\n", command); result_alter = dbi_conn_query(dbi->conn, command); if (!result_alter) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when upgrading engine to innoDB (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result_alter); } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 1"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v2(struct og_dbi *dbi) { const char *msglog; dbi_result result; int ret, i; ret = dbi_conn_transaction_begin(dbi->conn); if (ret) { syslog(LOG_DEBUG, "could not begin a transaction (%s:%d)\n", __func__, __LINE__); goto err_no_trans; } for (i = 0; i < OG_SCHEMA_STMTS_V2; i++) { result = dbi_conn_query(dbi->conn, stmts_v2[i]); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_ERR, "Statement number %d failed (%s:%d): %s\n", i, __func__, __LINE__, msglog); goto err_trans; } dbi_result_free(result); } ret = dbi_conn_transaction_commit(dbi->conn); if (ret) { syslog(LOG_DEBUG, "could not commit a transaction (%s:%d)\n", __func__, __LINE__); goto err_trans; } return 0; err_trans: dbi_conn_transaction_rollback(dbi->conn); err_no_trans: return -1; } static int og_dbi_schema_v3(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Adding disk type to ordenadores_particiones\n"); result = dbi_conn_query(dbi->conn, "ALTER TABLE ordenadores_particiones " "ADD disk_type VARCHAR(32) DEFAULT NULL " "AFTER numdisk;"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when adding disk type (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 3"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v4(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Adding identorno to ordenadores\n"); result = dbi_conn_query(dbi->conn, "ALTER TABLE `ordenadores` " "ADD `identorno` int(11) NOT NULL DEFAULT '1' " "AFTER `idordenador`, " "ADD CONSTRAINT `FK_entornos` " "FOREIGN KEY (`identorno`) " "REFERENCES `entornos` (`identorno`) " "ON DELETE RESTRICT;"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when adding identorno (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 4"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v5(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Adding size, lastupdate and permissions to imagenes\n"); result = dbi_conn_query(dbi->conn, "ALTER TABLE `imagenes` " "ADD `size` bigint DEFAULT '0' AFTER `datasize`, " "ADD `lastupdate` bigint DEFAULT '0' AFTER `size`, " "ADD `permissions` int DEFAULT '0' AFTER `lastupdate`;"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when updating imagenes table (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 5"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v6(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "create table cache\n"); result = dbi_conn_query(dbi->conn, "CREATE TABLE `cache` (" "`cacheid` int NOT NULL AUTO_INCREMENT," "`clientid` int NOT NULL DEFAULT 0," "`imagename` varchar(80) NOT NULL DEFAULT ''," "`size` bigint NOT NULL DEFAULT 0," "`checksum` varchar(128) NOT NULL DEFAULT ''," "PRIMARY KEY (`cacheid`)" ") AUTO_INCREMENT=1;"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error creating table cache (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 6"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v7(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Adding checksum to imagenes\n"); result = dbi_conn_query(dbi->conn, "ALTER TABLE `imagenes` " "ADD `checksum` varchar(128) NOT NULL DEFAULT ''"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when adding checksum (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 7"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v8(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Creating table image_scope\n"); result = dbi_conn_query(dbi->conn, "CREATE TABLE `image_scope` (" "`id` int NOT NULL AUTO_INCREMENT," "`image_id` int NOT NULL," "`scope_id` int NOT NULL," "PRIMARY KEY (`id`)," "FOREIGN KEY (`image_id`) REFERENCES `imagenes` (`idimagen`) ON DELETE CASCADE," "FOREIGN KEY (`scope_id`) REFERENCES `centros` (`idcentro`) ON DELETE CASCADE" ") AUTO_INCREMENT=1;"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when creating image_scope (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 8"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v9(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Adding alias to repositorios\n"); result = dbi_conn_query(dbi->conn, "ALTER TABLE `repositorios` " "ADD `alias` int(11) NULL;"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when adding alias (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 9"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v10(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Creating table boot_entries\n"); result = dbi_conn_query(dbi->conn, "CREATE TABLE `boot_entries` (" "`id` BIGINT NOT NULL AUTO_INCREMENT," "`client_id` INT NOT NULL," "`name` VARCHAR(255)," "`active` BOOLEAN," "`description` TEXT," "`entry_order` INT," "PRIMARY KEY (`id`)," "FOREIGN KEY (`client_id`) REFERENCES `ordenadores` (`idordenador`) ON DELETE CASCADE" ")"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when creating boot_entries (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 10"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static int og_dbi_schema_v11(struct og_dbi *dbi) { const char *msglog; dbi_result result; syslog(LOG_DEBUG, "Adding free_size and used_size to ordenadores_particiones\n"); result = dbi_conn_query(dbi->conn, "ALTER TABLE `ordenadores_particiones` " "ADD `used_size` BIGINT DEFAULT '0' AFTER `cache`, " "ADD `free_size` BIGINT DEFAULT '0' AFTER `used_size`;"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Error when updating ordenadores_particiones table (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 11"); if (!result) { dbi_conn_error(dbi->conn, &msglog); syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n", __func__, __LINE__, msglog); return -1; } dbi_result_free(result); return 0; } static struct og_schema_version { int version; int (*update)(struct og_dbi *dbi); } schema_version[] = { { .version = 1, .update = og_dbi_schema_v1 }, { .version = 2, .update = og_dbi_schema_v2 }, { .version = 3, .update = og_dbi_schema_v3 }, { .version = 4, .update = og_dbi_schema_v4 }, { .version = 5, .update = og_dbi_schema_v5 }, { .version = 6, .update = og_dbi_schema_v6 }, { .version = 7, .update = og_dbi_schema_v7, }, { .version = 8, .update = og_dbi_schema_v8, }, { .version = 9, .update = og_dbi_schema_v9, }, { .version = 10, .update = og_dbi_schema_v10,}, { .version = 11, .update = og_dbi_schema_v11,}, { 0, NULL }, }; int og_dbi_schema_update(void) { int version, i, err; struct og_dbi *dbi; dbi = og_dbi_open(&ogconfig.db); if (!dbi) { syslog(LOG_ERR, "cannot open a database connection (%s:%d)\n", __func__, __LINE__); return -1; } version = og_dbi_schema_version(dbi); if (version < 0) { syslog(LOG_INFO, "creating table version in schema\n"); og_dbi_create_version(dbi); } else { syslog(LOG_INFO, "database schema version %d\n", version); } for (i = 0; schema_version[i].version; i++) { if (version >= schema_version[i].version) continue; syslog(LOG_INFO, "upgrading to schema version %d\n", schema_version[i].version); err = schema_version[i].update(dbi); if (err < 0) { syslog(LOG_ERR, "failed to update schema!\n"); og_dbi_close(dbi); return -1; } } og_dbi_close(dbi); return 0; }