PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/states/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/states/sqlite3.py |
""" Management of SQLite3 databases =============================== .. versionadded:: 2016.3.0 :depends: - SQLite3 Python Module :configuration: See :py:mod:`salt.modules.sqlite3` for setup instructions The sqlite3 module is used to create and manage sqlite3 databases and execute queries Here is an example of creating a table using sql statements: .. code-block:: yaml users: sqlite3.table_present: - db: /var/www/data/app.sqlite - schema: CREATE TABLE `users` (`username` TEXT COLLATE NOCASE UNIQUE NOT NULL, `password` BLOB NOT NULL, `salt` BLOB NOT NULL, `last_login` INT) Here is an example of creating a table using yaml/jinja instead of sql: .. code-block:: yaml users: sqlite3.table_present: - db: /var/www/app.sqlite - schema: - email TEXT COLLATE NOCASE UNIQUE NOT NULL - firstname TEXT NOT NULL - lastname TEXT NOT NULL - company TEXT NOT NULL - password BLOB NOT NULL - salt BLOB NOT NULL Here is an example of making sure a table is absent: .. code-block:: yaml badservers: sqlite3.table_absent: - db: /var/www/data/users.sqlite Sometimes you would to have specific data in tables to be used by other services Here is an example of making sure rows with specific data exist: .. code-block:: yaml user_john_doe_xyz: sqlite3.row_present: - db: /var/www/app.sqlite - table: users - where_sql: email='john.doe@companyxyz.com' - data: email: john.doe@companyxyz.com lastname: doe firstname: john company: companyxyz.com password: abcdef012934125 salt: abcdef012934125 - require: - sqlite3: users Here is an example of removing a row from a table: .. code-block:: yaml user_john_doe_abc: sqlite3.row_absent: - db: /var/www/app.sqlite - table: users - where_sql: email="john.doe@companyabc.com" - require: - sqlite3: users Note that there is no explicit state to perform random queries, however, this can be approximated with sqlite3's module functions and module.run: .. code-block:: yaml zone-delete: module.run: - name: sqlite3.modify - db: {{ db }} - sql: "DELETE FROM records WHERE id > {{ count[0] }} AND domain_id = {{ domain_id }}" - watch: - sqlite3: zone-insert-12 """ try: import sqlite3 HAS_SQLITE3 = True except ImportError: HAS_SQLITE3 = False def __virtual__(): """ Only load if the sqlite3 module is available """ if HAS_SQLITE3: return True return (False, "Unable to import sqlite3") def row_absent(name, db, table, where_sql, where_args=None): """ Makes sure the specified row is absent in db. If multiple rows match where_sql, then the state will fail. name Only used as the unique ID db The database file name table The table name to check where_sql The sql to select the row to check where_args The list parameters to substitute in where_sql """ changes = {"name": name, "changes": {}, "result": None, "comment": ""} conn = None try: conn = sqlite3.connect(db, detect_types=sqlite3.PARSE_DECLTYPES) conn.row_factory = _dict_factory rows = None if where_args is None: rows = _query(conn, "SELECT * FROM `" + table + "` WHERE " + where_sql) else: rows = _query( conn, "SELECT * FROM `" + table + "` WHERE " + where_sql, where_args ) if len(rows) > 1: changes["result"] = False changes["comment"] = "More than one row matched the specified query" elif len(rows) == 1: if __opts__["test"]: changes["result"] = True changes["comment"] = "Row will be removed in " + table changes["changes"]["old"] = rows[0] else: if where_args is None: cursor = conn.execute( "DELETE FROM `" + table + "` WHERE " + where_sql ) else: cursor = conn.execute( "DELETE FROM `" + table + "` WHERE " + where_sql, where_args ) conn.commit() if cursor.rowcount == 1: changes["result"] = True changes["comment"] = "Row removed" changes["changes"]["old"] = rows[0] else: changes["result"] = False changes["comment"] = "Unable to remove row" else: changes["result"] = True changes["comment"] = "Row is absent" except Exception as e: # pylint: disable=broad-except changes["result"] = False changes["comment"] = str(e) finally: if conn: conn.close() return changes def row_present(name, db, table, data, where_sql, where_args=None, update=False): """ Checks to make sure the given row exists. If row exists and update is True then row will be updated with data. Otherwise it will leave existing row unmodified and check it against data. If the existing data doesn't match data_check the state will fail. If the row doesn't exist then it will insert data into the table. If more than one row matches, then the state will fail. name Only used as the unique ID db The database file name table The table name to check the data data The dictionary of key/value pairs to check against if row exists, insert into the table if it doesn't where_sql The sql to select the row to check where_args The list parameters to substitute in where_sql update True will replace the existing row with data When False and the row exists and data does not equal the row data then the state will fail """ changes = {"name": name, "changes": {}, "result": None, "comment": ""} conn = None try: conn = sqlite3.connect(db, detect_types=sqlite3.PARSE_DECLTYPES) conn.row_factory = _dict_factory rows = None if where_args is None: rows = _query(conn, "SELECT * FROM `" + table + "` WHERE " + where_sql) else: rows = _query( conn, "SELECT * FROM `" + table + "` WHERE " + where_sql, where_args ) if len(rows) > 1: changes["result"] = False changes["comment"] = "More than one row matched the specified query" elif len(rows) == 1: for key, value in data.items(): if key in rows[0] and rows[0][key] != value: if update: if __opts__["test"]: changes["result"] = True changes["comment"] = "Row will be update in " + table else: columns = [] params = [] for key, value in data.items(): columns.append("`" + key + "`=?") params.append(value) if where_args is not None: params += where_args sql = "UPDATE `" + table + "` SET " sql += ",".join(columns) sql += " WHERE " sql += where_sql cursor = conn.execute(sql, params) conn.commit() if cursor.rowcount == 1: changes["result"] = True changes["comment"] = "Row updated" changes["changes"]["old"] = rows[0] changes["changes"]["new"] = data else: changes["result"] = False changes["comment"] = "Row update failed" else: changes["result"] = False changes["comment"] = ( "Existing data does" + "not match desired state" ) break if changes["result"] is None: changes["result"] = True changes["comment"] = "Row exists" else: if __opts__["test"]: changes["result"] = True changes["changes"]["new"] = data changes["comment"] = "Row will be inserted into " + table else: columns = [] value_stmt = [] values = [] for key, value in data.items(): value_stmt.append("?") values.append(value) columns.append("`" + key + "`") sql = "INSERT INTO `" + table + "` (" sql += ",".join(columns) sql += ") VALUES (" sql += ",".join(value_stmt) sql += ")" cursor = conn.execute(sql, values) conn.commit() if cursor.rowcount == 1: changes["result"] = True changes["changes"]["new"] = data changes["comment"] = "Inserted row" else: changes["result"] = False changes["comment"] = "Unable to insert data" except Exception as e: # pylint: disable=broad-except changes["result"] = False changes["comment"] = str(e) finally: if conn: conn.close() return changes def table_absent(name, db): """ Make sure the specified table does not exist name The name of the table db The name of the database file """ changes = {"name": name, "changes": {}, "result": None, "comment": ""} conn = None try: conn = sqlite3.connect(db, detect_types=sqlite3.PARSE_DECLTYPES) tables = _query( conn, "SELECT sql FROM sqlite_master " + " WHERE type='table' AND name=?", [name], ) if len(tables) == 1: if __opts__["test"]: changes["result"] = True changes["comment"] = "'" + name + "' will be dropped" else: conn.execute("DROP TABLE " + name) conn.commit() changes["changes"]["old"] = tables[0][0] changes["result"] = True changes["comment"] = "'" + name + "' was dropped" elif len(tables) == 0: changes["result"] = True changes["comment"] = "'" + name + "' is already absent" else: changes["result"] = False changes["comment"] = "Multiple tables with the same name='" + name + "'" except Exception as e: # pylint: disable=broad-except changes["result"] = False changes["comment"] = str(e) finally: if conn: conn.close() return changes def table_present(name, db, schema, force=False): """ Make sure the specified table exists with the specified schema name The name of the table db The name of the database file schema The dictionary containing the schema information force If the name of the table exists and force is set to False, the state will fail. If force is set to True, the existing table will be replaced with the new table """ changes = {"name": name, "changes": {}, "result": None, "comment": ""} conn = None try: conn = sqlite3.connect(db, detect_types=sqlite3.PARSE_DECLTYPES) tables = _query( conn, "SELECT sql FROM sqlite_master " + "WHERE type='table' AND name=?", [name], ) if len(tables) == 1: sql = None if isinstance(schema, str): sql = schema.strip() else: sql = _get_sql_from_schema(name, schema) if sql != tables[0][0]: if force: if __opts__["test"]: changes["result"] = True changes["changes"]["old"] = tables[0][0] changes["changes"]["new"] = sql changes["comment"] = "'" + name + "' will be replaced" else: conn.execute("DROP TABLE `" + name + "`") conn.execute(sql) conn.commit() changes["result"] = True changes["changes"]["old"] = tables[0][0] changes["changes"]["new"] = sql changes["comment"] = "Replaced '" + name + "'" else: changes["result"] = False changes["comment"] = ( "Expected schema=" + sql + "\nactual schema=" + tables[0][0] ) else: changes["result"] = True changes["comment"] = "'" + name + "' exists with matching schema" elif len(tables) == 0: # Create the table sql = None if isinstance(schema, str): sql = schema else: sql = _get_sql_from_schema(name, schema) if __opts__["test"]: changes["result"] = True changes["changes"]["new"] = sql changes["comment"] = "'" + name + "' will be created" else: conn.execute(sql) conn.commit() changes["result"] = True changes["changes"]["new"] = sql changes["comment"] = "Created table '" + name + "'" else: changes["result"] = False changes["comment"] = "Multiple tables with the same name=" + name except Exception as e: # pylint: disable=broad-except changes["result"] = False changes["comment"] = str(e) finally: if conn: conn.close() return changes def _query(conn, sql, parameters=None): cursor = None if parameters is None: cursor = conn.execute(sql) else: cursor = conn.execute(sql, parameters) return cursor.fetchall() def _get_sql_from_schema(name, schema): return "CREATE TABLE `" + name + "` (" + ",".join(schema) + ")" def _dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): d[col[0]] = row[idx] return d