added a bootstrap.txt template file, and got rid of the old deploy_meta
This commit is contained in:
parent
dbc5638eac
commit
cf424da881
4 changed files with 11 additions and 589 deletions
|
|
@ -1,497 +0,0 @@
|
|||
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])
|
||||
|
||||
print("path_config_full: %s" % path_config_full)
|
||||
|
||||
configuration_file = yaml.safe_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()
|
||||
90
bin/test.py
90
bin/test.py
|
|
@ -1,90 +0,0 @@
|
|||
import ruamel.yaml
|
||||
import os
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--file1', default='development.yml')
|
||||
parser.add_argument('--file2', default='test.yml')
|
||||
|
||||
|
||||
def findDiff(d1, d2, path=""):
|
||||
for k in d1.keys():
|
||||
if not (k in d2):
|
||||
print(path, ":")
|
||||
print(k + " as key not in d2", "\n")
|
||||
else:
|
||||
if type(d1[k]) is dict:
|
||||
if path == "":
|
||||
path = k
|
||||
else:
|
||||
path = path + "->" + k
|
||||
findDiff(d1[k], d2[k], path)
|
||||
else:
|
||||
if d1[k] != d2[k]:
|
||||
print(path, ":")
|
||||
print(" - ", k, " : ", d1[k])
|
||||
print(" + ", k, " : ", d2[k])
|
||||
|
||||
|
||||
def compare_dictionaries(dict_1, dict_2, dict_1_name, dict_2_name, path=""):
|
||||
"""Compare two dictionaries recursively to find non mathcing elements
|
||||
|
||||
Args:
|
||||
dict_1: dictionary 1
|
||||
dict_2: dictionary 2
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
err = ''
|
||||
key_err = ''
|
||||
value_err = ''
|
||||
old_path = path
|
||||
for k in dict_1.keys():
|
||||
path = old_path + "[%s]" % k
|
||||
if not (k in dict_2):
|
||||
key_err += "Key %s%s not in %s\n" % (
|
||||
dict_2_name, path, dict_2_name)
|
||||
else:
|
||||
if isinstance(dict_1[k], dict) and isinstance(dict_2[k], dict):
|
||||
err += compare_dictionaries(
|
||||
dict_1[k], dict_2[k], 'd1', 'd2', path)
|
||||
else:
|
||||
if dict_1[k] != dict_2[k]:
|
||||
value_err += "Value of %s%s (%s) not same as %s%s (%s)\n"\
|
||||
% (dict_1_name,
|
||||
path, dict_1[k], dict_2_name, path, dict_2[k])
|
||||
|
||||
for k in dict_2.keys():
|
||||
path = old_path + "[%s]" % k
|
||||
if not (k in dict_1):
|
||||
key_err += "Key %s%s not in %s\n" % (
|
||||
dict_2_name, path, dict_1_name)
|
||||
|
||||
return key_err + value_err + err
|
||||
|
||||
|
||||
def create_path(path_str, delimiter="/"):
|
||||
path = ''
|
||||
|
||||
for d in path_str.split(delimiter):
|
||||
path = os.path.join(path, d)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
def main():
|
||||
path_meta = create_path("../../../meta/project")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
path_main = os.path.join(path_meta, args.file1)
|
||||
path_test = os.path.join(path_meta, args.file2)
|
||||
|
||||
yaml_main = ruamel.yaml.load(file(path_main, 'r'))
|
||||
yaml_test = ruamel.yaml.load(file(path_test, 'r'))
|
||||
|
||||
a = compare_dictionaries(yaml_main, yaml_test, 'main', 'test')
|
||||
print(a)
|
||||
|
||||
main()
|
||||
6
share/templates/meta/bootstrap.txt
Normal file
6
share/templates/meta/bootstrap.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Django
|
||||
PyYAML
|
||||
psycopg2
|
||||
pycryptodome
|
||||
gunicorn
|
||||
Jinja2
|
||||
|
|
@ -24,9 +24,12 @@ logging:
|
|||
paths: [null]
|
||||
maintenance:
|
||||
nginx:
|
||||
commands: {start: nginx, status: ps waux | grep nginx, stop: nginx -s stop}
|
||||
commands:
|
||||
start: brew services start nginx
|
||||
status: brew services list | grep nginx
|
||||
stop: brew services stop nginx
|
||||
editor: mvim
|
||||
execute: sudo
|
||||
execute: local
|
||||
supervisor:
|
||||
commands: {reload: supervisorctl reload, start: supervisorctl start, status: supervisorctl
|
||||
status, stop: supervisorctl stop, update: supervisorctl update}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue