fabric/bin/deploy_meta.py

495 lines
14 KiB
Python

import os
import sys
import yaml
from PyQt5.QtWidgets import QMainWindow, QLineEdit, QLabel, QAction
from PyQt5.QtWidgets import QFileDialog, QGridLayout, QWidget, QApplication
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtCore import QVariant
class DictQuery(dict):
# https://www.haykranen.nl/2016/02/13/handling-complex
# -nested-dicts-in-python/
def get(self, path, default=None):
keys = path.split(".")
val = None
for key in keys:
if val:
if isinstance(val, list):
val = [v.get(key, default) if v else None for v in val]
else:
val = val.get(key, default)
else:
val = dict.get(self, key, default)
if not val:
break
return val
def create_path(path_str, delimiter="/"):
"""
helper function to crate a path from a string
Keword Arguments:
path_str -- a "/" separated path
delimiter -- you can use a different delimiter
"""
path = ''
for d in path_str.split(delimiter):
path = os.path.join(path, d)
return path
def nested_path(dic, path, value, delimiter='.'):
"""
sets the value in a dictionary object given a string key
separated by '.'
Keyword Arguments:
path -- the string key whose path is separated by '.'
value -- the value we wish to set
delimiter -- the delimeter value used to separate the path
"""
keys = path.split('.')
return nested_set(dic, keys, value)
def nested_set(dic, keys, value):
"""
sets the value in a dictionary object given a list object
of keys
Keyword Arguments:
dic -- the dictionary object
keys -- the list object of keys
value -- the value we wish to set
"""
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
class DeployMeta(QMainWindow):
PATH_META = "../../../meta/project"
PATH_TEMPLATES = "../share/templates/meta"
path_meta = None
path_templates = None
default_store_file = "test.yml"
currentbranch = None
config_data = None
CONFIG_TYPES = {
'development': 'development.yml',
'staging': 'staging.yml',
'production': 'staging.yml',
}
widgets = None
widgets_baseinfo = {
'PROJECT_NAME': {
'title': 'Project Name',
'location': 'project.name',
},
'PROJECT_IP': {
'title': 'Project Host',
'location': 'project.host',
},
'BRANCH_NAME': {
'title': 'Branch Name',
'location': 'project.branch',
'default': {
'development': "development",
'staging': "staging",
'production': "production"
}
},
'BRANCH_EXT': {
'title': 'Branch Extension',
'location': 'project.extension',
'default': {
"development": "dev",
"staging": "stg",
"production": "prd"
}
},
'BRANCH_USER': {
'title': 'Branch User',
'location': 'project.user',
'default': {
"development": "ronny",
"staging": "website",
"production": "website"
}
},
'BRANCH_GROUP': {
'title': 'Branch Group',
'location': 'project.group',
'default': {
"development": "wheel",
"staging": "www-data",
"production": "www-data"
}
},
'DATABASE_IP': {
'title': 'Database IP',
'location': 'database.host'},
'DATABASE_PORT': {
'title': 'Database Port',
'location': 'database.port',
'default': {
'development': 'DOCKER_PORT',
"staging": "5432",
"production": "5432"
},
},
'DATABASE_NAME': {
'title': 'Database Name',
'location': 'database.name',
},
'DATABASE_ADMIN_NAME': {
'title': 'Database Admin Name',
'location': 'database.users.admin.name',
'default': {
"development": "admin",
"staging": "admin",
"production": "admin"
}
},
'DATABASE_ADMIN_PASS': {
'title': 'Database Admin Pass',
'location': 'database.users.admin.pass',
'default': {
'development': "admin",
'staging': "admin",
'production': "admin"
}
},
'DATABASE_USER_NAME': {
'title': 'Database User Name',
'location': 'database.users.default.name',
'default': {
'development': "ronny",
'staging': "website",
'production': "website"
}
},
'DATABASE_USER_PASS': {
'title': 'Database User Pass',
'location': 'database.users.default.pass',
'default': {
'development': "admin",
'staging': "admin",
'production': "admin",
}
},
'DJANGO_IP': {
'title': 'Django IP Address',
'location': 'django.host',
'default': {
'development': "127.0.0.1",
'staging': None,
'production': None
}
},
'DJANGO_PORT': {
'title': 'Django Port',
'location': 'django.port',
'default': {
'development': None,
'staging': "8000",
'production': "8010",
},
},
'NGINX_PORT': {
'title': 'Nginx Port',
'location': 'nginx.port',
'default': {
'development': "8080",
'staging': "80",
'production': "80",
},
}
}
def __init__(self):
super(DeployMeta, self).__init__()
# create the base path variables
self.path_meta = create_path(self.PATH_META)
self.path_templates = create_path(self.PATH_TEMPLATES)
self.widgets = dict()
for key in self.widgets_baseinfo:
self.widgets[key] = dict()
self.widgets[key]['title'] = self.widgets_baseinfo[key]['title']
self.widgets[key]['location'] = \
self.widgets_baseinfo[key]['location']
if 'default' in self.widgets_baseinfo[key]:
self.widgets[key]['default'] = \
self.widgets_baseinfo[key]['default']
else:
self.widgets[key]['default'] = None
self.widgets[key]['field'] = None
self.initUI()
def load_config(self, configname):
if configname not in self.CONFIG_TYPES.keys():
print("\nerror, load_config was called with parameter: {confname},"
"which is not a legitimate value in CONFIG TYPES."
"\nLegitimate values are {configvalues}".format(
confname=configname,
configvalues=self.CONFIG_TYPES.keys()))
sys.exit()
path_config_full = os.path.join(
self.path_templates, self.CONFIG_TYPES[configname])
configuration_file = yaml.load(open(path_config_full, 'r'))
return configuration_file
def store_config(self):
for key in self.widgets:
configvalue = str(self.widgets[key]['field'].text().__str__())
if configvalue.isdigit():
configvalue = int(configvalue)
nested_path(
self.config_data,
self.widgets[key]['location'],
configvalue)
dquery = DictQuery(self.config_data)
database_name = "{projectname}_{branchext}".format(
projectname=dquery.get('project.name'),
branchext=dquery.get('project.extension'))
virtualenv_name = "{projectname}_{branchext}".format(
projectname=dquery.get('project.name'),
branchext=dquery.get('project.extension'))
nested_path(
self.config_data, 'database.name', database_name)
nested_path(
self.config_data, 'virtualenv.name', virtualenv_name)
if self.currentbranch == 'development':
projectpath = "{projectname}.prj".format(
projectname=dquery.get('project.name'))
nested_path(
self.config_data, 'project.paths.home', projectpath)
nested_path(
self.config_data, 'virtualenv.name',
dquery.get('project.name'))
def add_widgetrow(self, key, grid):
row = grid.rowCount()
title = self.widgets[key]['title']
label = QLabel(title)
field = QLineEdit()
grid.addWidget(label, row, 0)
grid.addWidget(field, row, 1)
self.widgets[key]['field'] = field
def create_action(self, key):
title = key.capitalize()
menuname = "&%s" % title
shortcut = "Ctrl+%s" % title[0]
desc = "Load Configuration %s" % title
loadAction = QAction(menuname, self)
loadAction.setShortcut(shortcut)
loadAction.setStatusTip(desc)
loadAction.triggered.connect(self.action_loadconfig)
variant = QVariant(key)
loadAction.setData(variant)
return loadAction
def action_loadconfig(self):
sender = self.sender()
if type(sender.data()) is str:
self.currentbranch = sender.data()
else:
self.currentbranch = sender.data().toString().__str__()
self.config_data = self.load_config(self.currentbranch)
dquery = DictQuery(self.config_data)
for key in self.widgets:
configvalue = dquery.get(self.widgets[key]['location'])
if self.widgets[key]['default']:
defaultvalue = self.widgets[key]['default'][self.currentbranch]
if configvalue == key and defaultvalue is not None:
self.widgets[key]['field'].setText(defaultvalue)
else:
self.widgets[key]['field'].setText(str(configvalue))
else:
self.widgets[key]['field'].setText(configvalue)
def action_save_config(self):
# first make sure we've loaded up a configuration
# file to save. currentbranch will be set if we
# loaded it up
if self.currentbranch:
self.store_config()
# path_newconfig = os.path.join(
# self.path_meta, self.default_store_file)
dialog_title = "Save {currentbranch} configuration".format(
currentbranch=self.currentbranch)
#
# generate the default path to save to
path_default_save = os.path.join(
self.path_meta, self.default_store_file)
#
# get the path value from the dialog box
path_newconfig = QFileDialog.getSaveFileName(
self, dialog_title,
path_default_save,
filter='*.yml')
#
# if the user hit 'cancel' path_newconfig will be empty
if path_newconfig:
stream = open(path_newconfig[0], 'w')
yaml.dump(self.config_data, stream)
else:
#
# display message warning no configuration has been loaded
msg = QMessageBox()
msg.setIcon(QMessageBox.Warning)
msg.setText('Save Error')
msg.setInformativeText(
"Cannot save modified configuration until you load one of the"
" default config types")
retval = msg.exec_()
print("value of qmessagebox in action_save: %s" % retval)
def setupMenu(self):
menubar = self.menuBar()
menubar.setNativeMenuBar(False)
exitAction = QAction('&Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip("Exit application")
exitAction.triggered.connect(self.close)
saveAction = QAction('&Gore', self)
saveAction.setShortcut('Ctrl+T')
saveAction.setStatusTip("Save Config File")
saveAction.triggered.connect(self.action_save_config)
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
fileMenu.addAction(saveAction)
loadMenu = menubar.addMenu("&Load Configuration")
for key in self.CONFIG_TYPES:
loadMenu.addAction(self.create_action(key))
def initUI(self):
self.setupMenu()
grid = QGridLayout()
grid.setSpacing(10)
self.add_widgetrow('PROJECT_NAME', grid)
self.add_widgetrow('PROJECT_IP', grid)
self.add_widgetrow('BRANCH_NAME', grid)
self.add_widgetrow('BRANCH_EXT', grid)
self.add_widgetrow('BRANCH_USER', grid)
self.add_widgetrow('BRANCH_GROUP', grid)
self.add_widgetrow('DATABASE_IP', grid)
self.add_widgetrow('DATABASE_PORT', grid)
self.add_widgetrow('DATABASE_NAME', grid)
self.add_widgetrow('DATABASE_ADMIN_NAME', grid)
self.add_widgetrow('DATABASE_ADMIN_PASS', grid)
self.add_widgetrow('DATABASE_USER_NAME', grid)
self.add_widgetrow('DATABASE_USER_PASS', grid)
self.add_widgetrow('DJANGO_IP', grid)
self.add_widgetrow('DJANGO_PORT', grid)
self.add_widgetrow('NGINX_PORT', grid)
central = QWidget()
central.setLayout(grid)
self.setCentralWidget(central)
self.setGeometry(300, 300, 450, 300)
self.setWindowTitle("Deploy Meta Files")
self.show()
self.raise_()
def main():
app = QApplication(sys.argv)
app.setStyle("cleanlooks")
ex = DeployMeta()
sys.exit(app.exec_())
print(ex)
if __name__ == '__main__':
main()