-- Create function to get configuration valueCREATEORREPLACEFUNCTIONget_config_value(p_setting_nameVARCHAR(100),p_environmentVARCHAR(20)DEFAULT'production')RETURNSTEXTAS$$DECLAREconfig_valueTEXT;BEGINSELECTsetting_valueINTOconfig_valueFROMconfiguration_settingsWHEREsetting_name=p_setting_nameANDenvironment=p_environment;RETURNconfig_value;END;$$LANGUAGEplpgsql;-- Create function to set configuration valueCREATEORREPLACEFUNCTIONset_config_value(p_setting_nameVARCHAR(100),p_setting_valueTEXT,p_setting_typeVARCHAR(20),p_environmentVARCHAR(20),p_descriptionTEXTDEFAULTNULL,p_is_sensitiveBOOLEANDEFAULTFALSE,p_changed_byVARCHAR(100)DEFAULTcurrent_user)RETURNSVOIDAS$$DECLAREold_valueTEXT;BEGIN-- Get old value for historySELECTsetting_valueINTOold_valueFROMconfiguration_settingsWHEREsetting_name=p_setting_nameANDenvironment=p_environment;-- Update or insert configurationINSERTINTOconfiguration_settings(setting_name,setting_value,setting_type,description,is_sensitive,environment)VALUES(p_setting_name,p_setting_value,p_setting_type,p_description,p_is_sensitive,p_environment)ONCONFLICT(setting_name,environment)DOUPDATESETsetting_value=EXCLUDED.setting_value,setting_type=EXCLUDED.setting_type,description=EXCLUDED.description,is_sensitive=EXCLUDED.is_sensitive,updated_at=CURRENT_TIMESTAMP;-- Record change in historyINSERTINTOconfiguration_history(setting_name,old_value,new_value,changed_by,change_reason)VALUES(p_setting_name,old_value,p_setting_value,p_changed_by,'Configuration updated');END;$$LANGUAGEplpgsql;
-- Create function to apply configuration templateCREATEORREPLACEFUNCTIONapply_configuration_template(p_template_nameVARCHAR(100),p_environmentVARCHAR(20),p_applied_byVARCHAR(100)DEFAULTcurrent_user)RETURNSINTEGERAS$$DECLAREtemplate_settingsJSONB;setting_keyTEXT;setting_valueTEXT;applied_countINTEGER:=0;BEGIN-- Get template settingsSELECTsettingsINTOtemplate_settingsFROMconfiguration_templatesWHEREtemplate_name=p_template_nameANDenvironment=p_environment;IFtemplate_settingsISNULLTHENRAISEEXCEPTION'Template % not found for environment %',p_template_name,p_environment;ENDIF;-- Apply each setting from templateFORsetting_key,setting_valueINSELECTkey,valueFROMjsonb_each_text(template_settings)LOOPPERFORMset_config_value(setting_key,setting_value,'string',p_environment,'Applied from template '||p_template_name,FALSE,p_applied_by);applied_count:=applied_count+1;ENDLOOP;RETURNapplied_count;END;$$LANGUAGEplpgsql;-- Create function to validate configurationCREATEORREPLACEFUNCTIONvalidate_configuration(p_environmentVARCHAR(20))RETURNSTABLE(setting_nameVARCHAR(100),statusTEXT,messageTEXT)AS$$BEGIN-- Check required settingsRETURNQUERYSELECT'max_connections'::VARCHAR(100),CASEWHENget_config_value('max_connections',p_environment)ISNOTNULLTHEN'PASS'ELSE'FAIL'END::TEXT,CASEWHENget_config_value('max_connections',p_environment)ISNOTNULLTHEN'max_connections is configured'ELSE'max_connections is missing'END::TEXT;RETURNQUERYSELECT'shared_buffers'::VARCHAR(100),CASEWHENget_config_value('shared_buffers',p_environment)ISNOTNULLTHEN'PASS'ELSE'FAIL'END::TEXT,CASEWHENget_config_value('shared_buffers',p_environment)ISNOTNULLTHEN'shared_buffers is configured'ELSE'shared_buffers is missing'END::TEXT;RETURNQUERYSELECT'wal_level'::VARCHAR(100),CASEWHENget_config_value('wal_level',p_environment)ISNOTNULLTHEN'PASS'ELSE'FAIL'END::TEXT,CASEWHENget_config_value('wal_level',p_environment)ISNOTNULLTHEN'wal_level is configured'ELSE'wal_level is missing'END::TEXT;END;$$LANGUAGEplpgsql;
# configuration/config_manager.pyimportpsycopg2importjsonimportyamlfromdatetimeimportdatetimeimportloggingclassPostgreSQLConfigManager:def__init__(self,connection_params):self.conn_params=connection_paramsself.setup_logging()defsetup_logging(self):"""Setup logging."""logging.basicConfig(level=logging.INFO)self.logger=logging.getLogger(__name__)defload_config_from_file(self,config_file):"""Load configuration from YAML file."""withopen(config_file,'r')asf:config=yaml.safe_load(f)returnconfigdefapply_configuration(self,config_data,environment):"""Apply configuration to database."""conn=psycopg2.connect(**self.conn_params)try:withconn.cursor()ascur:forsetting_name,setting_valueinconfig_data.items():cur.execute(""" SELECT set_config_value(%s, %s, %s, %s, %s, %s, %s) """,(setting_name,str(setting_value),'string',environment,f'Applied from config file',False,'config_manager'))conn.commit()self.logger.info(f"Configuration applied for environment {environment}")exceptExceptionase:self.logger.error(f"Configuration application failed: {e}")conn.rollback()raisefinally:conn.close()defget_configuration(self,environment):"""Get current configuration for environment."""conn=psycopg2.connect(**self.conn_params)try:withconn.cursor()ascur:cur.execute(""" SELECT setting_name, setting_value, setting_type, description FROM configuration_settings WHERE environment = %s ORDER BY setting_name """,(environment,))config=cur.fetchall()returnconfigexceptExceptionase:self.logger.error(f"Error getting configuration: {e}")return[]finally:conn.close()defvalidate_configuration(self,environment):"""Validate configuration for environment."""conn=psycopg2.connect(**self.conn_params)try:withconn.cursor()ascur:cur.execute("SELECT * FROM validate_configuration(%s)",(environment,))validation_results=cur.fetchall()returnvalidation_resultsexceptExceptionase:self.logger.error(f"Error validating configuration: {e}")return[]finally:conn.close()defrollback_configuration(self,environment,rollback_to_datetime):"""Rollback configuration to specific datetime."""conn=psycopg2.connect(**self.conn_params)try:withconn.cursor()ascur:# Get configuration state at rollback timecur.execute(""" SELECT DISTINCT ON (setting_name) setting_name, old_value FROM configuration_history WHERE changed_at <= %s ORDER BY setting_name, changed_at DESC """,(rollback_to_datetime,))rollback_settings=cur.fetchall()# Apply rollback settingsforsetting_name,old_valueinrollback_settings:ifold_valueisnotNone:cur.execute(""" SELECT set_config_value(%s, %s, %s, %s, %s, %s, %s) """,(setting_name,old_value,'string',environment,f'Rollback to {rollback_to_datetime}',False,'config_manager'))conn.commit()self.logger.info(f"Configuration rolled back for environment {environment}")exceptExceptionase:self.logger.error(f"Configuration rollback failed: {e}")conn.rollback()raisefinally:conn.close()# Usageif__name__=="__main__":config_manager=PostgreSQLConfigManager({'host':'localhost','database':'production','user':'config_user','password':'config_password'})# Load and apply configurationconfig_data=config_manager.load_config_from_file('config/production.yaml')config_manager.apply_configuration(config_data,'production')# Validate configurationvalidation_results=config_manager.validate_configuration('production')print(json.dumps(validation_results,indent=2))
-- Create function to create configuration templateCREATEORREPLACEFUNCTIONcreate_configuration_template(p_template_nameVARCHAR(100),p_environmentVARCHAR(20),p_settingsJSONB,p_descriptionTEXTDEFAULTNULL)RETURNSVOIDAS$$BEGININSERTINTOconfiguration_templates(template_name,environment,settings,description)VALUES(p_template_name,p_environment,p_settings,p_description)ONCONFLICT(template_name,environment)DOUPDATESETsettings=EXCLUDED.settings,description=EXCLUDED.description;END;$$LANGUAGEplpgsql;-- Create function to get configuration templateCREATEORREPLACEFUNCTIONget_configuration_template(p_template_nameVARCHAR(100),p_environmentVARCHAR(20))RETURNSJSONBAS$$DECLAREtemplate_settingsJSONB;BEGINSELECTsettingsINTOtemplate_settingsFROMconfiguration_templatesWHEREtemplate_name=p_template_nameANDenvironment=p_environment;RETURNtemplate_settings;END;$$LANGUAGEplpgsql;
-- Create function to validate configuration valuesCREATEORREPLACEFUNCTIONvalidate_configuration_value(p_setting_nameVARCHAR(100),p_setting_valueTEXT,p_setting_typeVARCHAR(20))RETURNSBOOLEANAS$$BEGIN-- Validate based on setting typeCASEp_setting_typeWHEN'integer'THENRETURNp_setting_value~'^\d+$';WHEN'boolean'THENRETURNp_setting_valueIN('true','false','on','off','yes','no');WHEN'size'THENRETURNp_setting_value~'^\d+[KMGT]?B?$';WHEN'time'THENRETURNp_setting_value~'^\d+[smhd]?$';ELSERETURNTRUE;-- String type, always validENDCASE;END;$$LANGUAGEplpgsql;-- Create function to validate all configurationCREATEORREPLACEFUNCTIONvalidate_all_configuration(p_environmentVARCHAR(20))RETURNSTABLE(setting_nameVARCHAR(100),setting_valueTEXT,setting_typeVARCHAR(20),is_validBOOLEAN,error_messageTEXT)AS$$BEGINRETURNQUERYSELECTcs.setting_name,cs.setting_value,cs.setting_type,validate_configuration_value(cs.setting_name,cs.setting_value,cs.setting_type)asis_valid,CASEWHENvalidate_configuration_value(cs.setting_name,cs.setting_value,cs.setting_type)THENNULLELSE'Invalid value for '||cs.setting_type||' type'ENDaserror_messageFROMconfiguration_settingscsWHEREcs.environment=p_environment;END;$$LANGUAGEplpgsql;
-- Create function to get configuration changesCREATEORREPLACEFUNCTIONget_configuration_changes(p_environmentVARCHAR(20),p_start_dateTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP-INTERVAL'7 days',p_end_dateTIMESTAMPTZDEFAULTCURRENT_TIMESTAMP)RETURNSTABLE(setting_nameVARCHAR(100),old_valueTEXT,new_valueTEXT,changed_byVARCHAR(100),change_reasonTEXT,changed_atTIMESTAMPTZ)AS$$BEGINRETURNQUERYSELECTch.setting_name,ch.old_value,ch.new_value,ch.changed_by,ch.change_reason,ch.changed_atFROMconfiguration_historychWHEREch.changed_atBETWEENp_start_dateANDp_end_dateORDERBYch.changed_atDESC;END;$$LANGUAGEplpgsql;-- Create function to get configuration driftCREATEORREPLACEFUNCTIONdetect_configuration_drift(p_environmentVARCHAR(20),p_template_nameVARCHAR(100))RETURNSTABLE(setting_nameVARCHAR(100),current_valueTEXT,template_valueTEXT,is_driftedBOOLEAN)AS$$DECLAREtemplate_settingsJSONB;BEGIN-- Get template settingsSELECTsettingsINTOtemplate_settingsFROMconfiguration_templatesWHEREtemplate_name=p_template_nameANDenvironment=p_environment;-- Compare current settings with templateRETURNQUERYSELECTcs.setting_name,cs.setting_valueascurrent_value,template_settings->>cs.setting_nameastemplate_value,(cs.setting_value!=(template_settings->>cs.setting_name))asis_driftedFROMconfiguration_settingscsWHEREcs.environment=p_environmentANDtemplate_settings?cs.setting_name;END;$$LANGUAGEplpgsql;