diff --git a/.gitignore b/.gitignore index d4777d2..eb47d31 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,8 @@ .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* @@ -26,3 +27,4 @@ Network Trash Folder Temporary Items .apdisk +**/Dokumentation.pdf diff --git a/README.md b/README.md index ca987bd..3590813 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ # KVM-Store-Server -This repository contains my diploma thesis for the postgraduate studies program at the Higher Education Institute (HF). It is a specialized key-value in-memory store, which was developed for a problem domain of a sponsoring company. \ No newline at end of file +**Attention, this project was created in 2018 and has never been ported to a more recent Go version.** + +**This project is for educational purposes only and should not be actively used. The project is not archived, but development is no longer ongoing.** + +**This project should no longer be used; there are far better alternatives available (etcd etc.).** + +*To protect the data privacy of the project sponsor, the entire documentation cannot be published here. However, the documentation has been reduced to an absolute minimum (user manual) to still be of some help.__* + +This repository contains my diploma thesis for the postgraduate studies program at the Higher Education Institute (HF). It is a specialized key-value in-memory store, which was developed for a problem domain of a sponsoring company. diff --git a/helper_bin/inject_client/src/checker/getLastEntry.go b/helper_bin/inject_client/src/checker/getLastEntry.go new file mode 100755 index 0000000..c35c61b --- /dev/null +++ b/helper_bin/inject_client/src/checker/getLastEntry.go @@ -0,0 +1,70 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: getLastEntry.go + * Version: 1.0.0 + * Date: 2018-01-15 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package checker + +import ( + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strconv" +) + +// GetRandomEntry ... +func GetRandomEntry(url string, lastEntry int) string { + + partialURL := url + "/get/System_Name_" + strconv.Itoa(lastEntry) + + resp, err := http.Get(partialURL) + if err != nil { + log.Printf("\nERROR: Destination URL (%v) does not answer (Error-> %v)", + partialURL, err) + os.Exit(1) + } + defer resp.Body.Close() + + if resp.StatusCode == 200 { + body, _ := ioutil.ReadAll(resp.Body) + return string(body) + } + + return fmt.Sprintf("Error: The status of the received message is unequal 200 (Received: %v)", + resp.StatusCode) +} diff --git a/helper_bin/inject_client/src/checker/urlChecker.go b/helper_bin/inject_client/src/checker/urlChecker.go new file mode 100755 index 0000000..4e2b638 --- /dev/null +++ b/helper_bin/inject_client/src/checker/urlChecker.go @@ -0,0 +1,61 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: urlChecker.go + * Version: 1.0.0 + * Date: 2018-01-15 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package checker + +import ( + "fmt" + "net/http" +) + +// IsURLValid ... +func IsURLValid(url string) error { + + fullURL := url + "/version" + + resp, err := http.Get(fullURL) + if err != nil { + return fmt.Errorf("Destination URL (%v) does not answer", url) + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusOK { + return nil + } + return fmt.Errorf("Something seems to be wrong with the server - Abort") +} diff --git a/helper_bin/inject_client/src/client/client.go b/helper_bin/inject_client/src/client/client.go new file mode 100755 index 0000000..4b70d60 --- /dev/null +++ b/helper_bin/inject_client/src/client/client.go @@ -0,0 +1,145 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: client.go + * Version: 1.0.0 + * Date: 2018-01-15 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package client + +import ( + "bytes" + "fmt" + "net/http" + "strconv" + "sync" + "time" +) + +//***************************************************************************** +//* +//* Structure: Synchronizer +//* +//***************************************************************************** + +// ParaController ... +type ParaController struct { + Wg sync.WaitGroup +} + +//***************************************************************************** +//* +//* Structure: InjClient +//* +//***************************************************************************** + +// InjClient ... +type InjClient struct { + clientID int + url string +} + +//******************** Methods ************************************************ + +// generateKeyName ... +func (slf *InjClient) generateKeyName() string { + return "System_Name_" + strconv.Itoa(slf.clientID) +} + +// GenerateRequest ... +func (slf *InjClient) generateRequest() *bytes.Reader { + + newName := slf.generateKeyName() + + newNbr := slf.clientID + newVers := float64(slf.clientID) + 0.99999999 + newAct := slf.clientID%2 == 0 + newNull := "null" + + return bytes.NewReader([]byte( + fmt.Sprintf(`{"system_name": "%v","system_number": %v,"system_version": %v,"system_active": %v,"system_null": %v}`, + newName, newNbr, newVers, newAct, newNull), + )) +} + +// StartRequest ... +func (slf *InjClient) StartRequest(syncer *ParaController) { + + defer func() { + err := recover() + if err != nil { + fmt.Printf("(RECOVER) Worker ID: %v - failed: Reason -> [Program Error: %v]\n", + slf.clientID, err) + + syncer.Wg.Add(-1) + } + }() + + client := &http.Client{Timeout: time.Second * 60} + callURL := slf.url + "/add/" + slf.generateKeyName() + + req, _ := http.NewRequest("POST", callURL, slf.generateRequest()) + req.Header.Set("User-Agent", "Injection-Client-storeserver-1.0.0") + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + + if err != nil { + fmt.Printf("Worker ID: %v - failed: Reason -> [Connection Error -> (%v)]\n", + slf.clientID, err) + return + } + if resp.StatusCode != 201 { + fmt.Printf("Worker ID: %v - failed: Reason -> [Status != 201 | (Received: %v)]\n", + resp.StatusCode, slf.clientID) + return + } + + resp.Body.Close() + syncer.Wg.Add(-1) +} + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewWorker ... +func NewWorker(clientID int, url string) *InjClient { + return &InjClient{ + clientID: clientID, + url: url, + } +} diff --git a/helper_bin/inject_client/src/inject_client/main.go b/helper_bin/inject_client/src/inject_client/main.go new file mode 100755 index 0000000..65f307e --- /dev/null +++ b/helper_bin/inject_client/src/inject_client/main.go @@ -0,0 +1,89 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: main.go + * Version: 1.0.0 + * Date: 2018-01-15 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "checker" + "client" + "fmt" + "runtime" + "time" + "utils" +) + +func main() { + + const maxParaReqs int = 6000 + var endNbr int + + cmdArgs := utils.NewCmdController() + synchronizer := client.ParaController{} + start := time.Now() + + if cmdArgs.GetStart() != 0 { + endNbr = cmdArgs.GetStart() + 6000 + } else { + endNbr = maxParaReqs + } + + for idx := cmdArgs.GetStart(); idx < endNbr; idx++ { + + synchronizer.Wg.Add(1) + go client.NewWorker(idx, cmdArgs.GetTarget()).StartRequest(&synchronizer) + } + synchronizer.Wg.Wait() + + runtime.GC() + + fmt.Printf("\nToral duration of all (%v) parallel requests -> %v\n", + maxParaReqs, time.Since(start)) + + fmt.Printf("\nThe default key pattern is \"System_Name_<%v - %v>\"", cmdArgs.GetStart(), endNbr-1) + fmt.Printf(` + + EXAMPLE: + http://:3344/get/System_Name_0 + `) + + fmt.Printf("Start trying to get the last entry from kvmstoreserver:") + + fmt.Printf("\nRESULT -> %v", + checker.GetRandomEntry(cmdArgs.GetTarget(), endNbr-1)) + +} diff --git a/helper_bin/inject_client/src/utils/cmdParser.go b/helper_bin/inject_client/src/utils/cmdParser.go new file mode 100755 index 0000000..3b5389a --- /dev/null +++ b/helper_bin/inject_client/src/utils/cmdParser.go @@ -0,0 +1,98 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: cmdParser.go + * Version: 1.0.0 + * Date: 2018-01-15 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package utils + +import ( + "checker" + "flag" + "fmt" + "log" + "os" +) + +//***************************************************************************** +//* +//* Structure: CmdController +//* +//***************************************************************************** + +// CmdController ... +type CmdController struct { + target *string + start *int +} + +//******************** Methods ************************************************ + +// GetTarget ... +func (slf *CmdController) GetTarget() string { return *slf.target } + +// GetStart ... +func (slf *CmdController) GetStart() int { return *slf.start } + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewCmdController ... +func NewCmdController() *CmdController { + + var cmdController CmdController + + cmdController.target = flag.String("target", "", + "The URL to the storeserver -> EXAMPLE: http://:3344") + + cmdController.start = flag.Int("start", 0, + "Please enter the start number. At this point + 6000 will be added") + + if cmdController.target == nil { + fmt.Println("Please enter the address of the server -> EXAMPLE: inject_client -target http://:3344") + os.Exit(1) + } + + flag.Parse() + + if err := checker.IsURLValid(*cmdController.target); err != nil { + log.Fatal(err) + } + + return &cmdController +} diff --git a/helper_bin/inject_disk/src/generator/jsonObjGenerator.go b/helper_bin/inject_disk/src/generator/jsonObjGenerator.go new file mode 100755 index 0000000..a499245 --- /dev/null +++ b/helper_bin/inject_disk/src/generator/jsonObjGenerator.go @@ -0,0 +1,121 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: jsonObjGenerator.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package generator + +import ( + "fmt" + "io/ioutil" + "keyNameHandling" + "log" + "strconv" + "utils" +) + +//***************************************************************************** +//* +//* Declarations +//* +//***************************************************************************** + +const namePattern string = "System_Name_" + +//***************************************************************************** +//* +//* Structure: JObjGenerator +//* +//***************************************************************************** + +// JObjGenerator ... +type JObjGenerator struct { + objNbr int + jObj []byte + wPath string + fullPath string + syncer *utils.ParaController +} + +//******************** Methods ************************************************ + +func (slf *JObjGenerator) generateJObj() { + + keyName := namePattern + strconv.Itoa(slf.objNbr) + nodeID, _ := keyNameHandling.NewKeyContext(keyName) + + slf.fullPath = slf.wPath + "/" + strconv.Itoa(nodeID.GetNodeID()) + ".json" + + dataNbr := slf.objNbr + dataVers := float64(slf.objNbr) + 0.99999999 + dataAct := slf.objNbr%2 == 0 + dataNull := "null" + + slf.jObj = []byte( + fmt.Sprintf(`{"node_id":%v,"orig_key_name":"%v","data_container":[{"rev_nbr":0,"meta_header":{"remote_addr":"0.0.0.0:65535","created_at":"1970-01-01T00:00:00.3889558+01:00"},"data":{"system_name": "%v","system_number": %v,"system_version": %v,"system_active": %v,"system_null": %v}}]}`, + nodeID.GetNodeID(), nodeID.GetKeyStrName(), nodeID.GetKeyStrName(), dataNbr, dataVers, dataAct, dataNull), + ) + +} + +// WriteIntoTarget ... +func (slf *JObjGenerator) WriteIntoTarget() { + + if err := ioutil.WriteFile(slf.fullPath, slf.jObj, 0660); err != nil { + log.Printf("Write for %v failed: Reason -> [%v]", slf.fullPath, err) + } + + slf.syncer.Wg.Add(-1) +} + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewWorker ... +func NewWorker(objNbr int, wPath *string, syncer *utils.ParaController) *JObjGenerator { + newObj := JObjGenerator{ + objNbr: objNbr, + wPath: *wPath, + syncer: syncer, + } + + newObj.generateJObj() + + return &newObj +} diff --git a/helper_bin/inject_disk/src/inject_disk/main.go b/helper_bin/inject_disk/src/inject_disk/main.go new file mode 100755 index 0000000..13b646d --- /dev/null +++ b/helper_bin/inject_disk/src/inject_disk/main.go @@ -0,0 +1,101 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: main.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "fmt" + "generator" + "time" + "utils" +) + +func main() { + + var ( + chunkSize int + outerLoops int + rest int + objCounter int + ) + + chunkSize = 10000 + + cmdArgs := utils.NewCmdController() + synchronizer := utils.NewParaController() + + if cmdArgs.GetObjects() < chunkSize { + chunkSize = cmdArgs.GetObjects() + outerLoops = 1 + rest = 0 + } else { + outerLoops = cmdArgs.GetObjects() / chunkSize + rest = cmdArgs.GetObjects() % chunkSize + } + + start := time.Now() + + for outerIdx := 0; outerIdx < outerLoops; outerIdx++ { + + for innerIdx := 0; innerIdx < chunkSize; innerIdx++ { + synchronizer.Wg.Add(1) + generator.NewWorker(objCounter, cmdArgs.GetTargetRef(), synchronizer). + WriteIntoTarget() + + objCounter++ + } + + synchronizer.Wg.Wait() + } + + if rest > 0 { + for innerIdx := 0; innerIdx < rest; innerIdx++ { + synchronizer.Wg.Add(1) + generator.NewWorker(objCounter, cmdArgs.GetTargetRef(), synchronizer). + WriteIntoTarget() + + objCounter++ + } + + synchronizer.Wg.Wait() + } + + fmt.Printf("%v generic JSON objects were generated in %v and stored in path -> %v\n", + objCounter, time.Since(start), *cmdArgs.GetTargetRef()) + +} diff --git a/helper_bin/inject_disk/src/keyNameHandling/KeyNameToIdConverter.go b/helper_bin/inject_disk/src/keyNameHandling/KeyNameToIdConverter.go new file mode 100755 index 0000000..1f4ba78 --- /dev/null +++ b/helper_bin/inject_disk/src/keyNameHandling/KeyNameToIdConverter.go @@ -0,0 +1,123 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: KeyNameToIdConverter.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package keyNameHandling + +// nolint +import ( + "crypto/md5" + "errors" + "strconv" + "strings" +) + +//***************************************************************************** +//* +//* Structure: keyContext +//* +//***************************************************************************** + +// KeyContext takes the original key and forms or calculates +// all necessary parameters. This holds it in, so you can access +// it from the outside +type keyContext struct { + keyNameAsString string + keyMd5Hash [16]byte + + // Here is the calculated node ID where the data should be stored + dataNodeID int +} + +/********************* Methods ************************************************/ + +// defDataNodeID ... +func (slf *keyContext) defDataNodeID() { + + var uniqueIdentifierStr string + + for idx := 0; idx < 6; idx++ { + uniqueIdentifierStr += strconv.Itoa(int(slf.keyMd5Hash[idx])) + } + + uniqueIdentifier, _ := strconv.ParseInt(uniqueIdentifierStr, 10, 64) + slf.dataNodeID = int(uniqueIdentifier) +} + +// nolint +// defChkSum calc the checksum from the name (in string form) +func (slf *keyContext) defChkSum() { + slf.keyMd5Hash = md5.Sum([]byte(slf.keyNameAsString)) +} + +/********************* Interface: IHandelWithIds ******************************/ + +// GetKeyStrName returns the plain text key name from the structure +func (slf *keyContext) GetKeyStrName() string { return slf.keyNameAsString } + +// GetNodeId returns the calculated Node ID from the structure +func (slf *keyContext) GetNodeID() int { return slf.dataNodeID } + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewKeyContext Returns a reference to the structure, which +// contains all information on the following points: +// +// - Original Key Name as string +// - MD5 hash of the key name +// - The ID of RootTree +// - The ID of the node where to save or read data +func NewKeyContext(key string) (IHandelWithIds, error) { + + var kc keyContext + + // A backup to prevent blank input + secKey := strings.Trim(key, " ") + if len(secKey) == 0 { + return &kc, errors.New("Key name is a empty string") + } + + kc.keyNameAsString = key + kc.defChkSum() + kc.defDataNodeID() + + return &kc, nil +} diff --git a/helper_bin/inject_disk/src/keyNameHandling/interfaces.go b/helper_bin/inject_disk/src/keyNameHandling/interfaces.go new file mode 100755 index 0000000..10edef4 --- /dev/null +++ b/helper_bin/inject_disk/src/keyNameHandling/interfaces.go @@ -0,0 +1,52 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: interfaces.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package keyNameHandling + +// IHandelWithIds works as a getter interface. This is +// necessary so that the structure keyContext does not +// have to be exported. So nobody can manipulate data +// into the structure. This interface only realizes read +// only capabilities +type IHandelWithIds interface { + // GetKeyStrName returns the value stored in the structure + GetKeyStrName() string + + // GetNodeID returns the value stored in the structure + GetNodeID() int +} diff --git a/helper_bin/inject_disk/src/utils/cmdParser.go b/helper_bin/inject_disk/src/utils/cmdParser.go new file mode 100755 index 0000000..37e8946 --- /dev/null +++ b/helper_bin/inject_disk/src/utils/cmdParser.go @@ -0,0 +1,85 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: cmdParser.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package utils + +import ( + "flag" +) + +//***************************************************************************** +//* +//* Structure: CmdController +//* +//***************************************************************************** + +// CmdController ... +type CmdController struct { + target *string + objects *int +} + +//******************** Methods ************************************************ + +// GetTargetRef ... +func (slf *CmdController) GetTargetRef() *string { return slf.target } + +// GetObjects ... +func (slf *CmdController) GetObjects() int { return *slf.objects } + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewCmdController ... +func NewCmdController() *CmdController { + + var cmdController CmdController + + cmdController.target = flag.String("target", "/home/kvmstoreserver/kvmstoreserver/warehouse", + "The path to the warehouse folder") + + cmdController.objects = flag.Int("objects", 1, + "How many json objects should be generated") + + flag.Parse() + + return &cmdController +} diff --git a/helper_bin/inject_disk/src/utils/paraController.go b/helper_bin/inject_disk/src/utils/paraController.go new file mode 100755 index 0000000..e6e6f5c --- /dev/null +++ b/helper_bin/inject_disk/src/utils/paraController.go @@ -0,0 +1,53 @@ +/************************************************************************************** + * + * Project: kvmstoreserver-tools + * File name: paraController.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver-tools. + * + * kvmstoreserver-tools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver-tools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver-tools. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package utils + +import ( + "sync" +) + +// ParaController ... +type ParaController struct { + Wg sync.WaitGroup +} + +// NewParaController ... +func NewParaController() *ParaController { + return &ParaController{} +} diff --git a/kvmstoreserver_installer/data/bin/kvmstoreserver b/kvmstoreserver_installer/data/bin/kvmstoreserver new file mode 100644 index 0000000..28d8331 Binary files /dev/null and b/kvmstoreserver_installer/data/bin/kvmstoreserver differ diff --git a/kvmstoreserver_installer/data/etc/kvmstoreserver.conf b/kvmstoreserver_installer/data/etc/kvmstoreserver.conf new file mode 100644 index 0000000..20a2300 --- /dev/null +++ b/kvmstoreserver_installer/data/etc/kvmstoreserver.conf @@ -0,0 +1,55 @@ +#****************************************************************************** +#* storeserver main config file +#****************************************************************************** + +#****************************************************************************** +#* The kvmstoreserver was compiled with the configPoller extension. This means +#* that changes to this config file can be captured after 60 seconds and +#* loaded at runtime of the kvmstoreserver. Not all of the parameters listed +#* below can be updated at runtime. Parameters with the comment label DYNAMIC +#* can be updated at runtime. Parameters with the label STATIC did not belong. +#* +#* Caution when updating DYNAMIC parameters. +#* In case of incorrect entries, the kvmstoreserver can crash! +#* +#****************************************************************************** + + +###################### General Server settings ################################ + +# DINAMIC +storage_target = /home/kvmstoreserver/kvmstoreserver/warehouse + +# DINAMIC +serde_driver = filesystem + +# All log file parameters -> STATIC +default_log_file = /home/kvmstoreserver/kvmstoreserver/var/log/kvmstoreserver.log +log_max_size_mb = 100 +log_max_age_days = 30 +log_write_to_console = false + + +######################### HTTP Server settings ############################### + +# All HTTP Server Settings -> STATIC +http_hostname = +http_port = 3344 +read_header_timeout = 30 +read_timeout = 30 +write_timeout = 30 +tcp_idle_timeout_millsec = 100 + +########################### Http Route settings ############################## +### Attention, the maximum path length per route is reduced to 1. Longer paths, +### such as /controller/add/ are not allowed and cause errors + +### All routes that work with JSON documents must always have an end slash in +### the name such as /add"/" + +# All Controller parameter -> STATIC +ctrl_add_path = /add/ +ctrl_get_path = /get/ +ctrl_del_path = /del/ +ctrl_tree_path = /tree +ctrl_version_path = /version \ No newline at end of file diff --git a/kvmstoreserver_installer/data/init/kvmstoreserver.service b/kvmstoreserver_installer/data/init/kvmstoreserver.service new file mode 100644 index 0000000..4d0a5ab --- /dev/null +++ b/kvmstoreserver_installer/data/init/kvmstoreserver.service @@ -0,0 +1,37 @@ +#************************************************************************************** +#* +#* Project: kvmstoreserver +#* File name: kvmstoreserver.service +#* Version: 1.0.0 +#* Date: 2018-02-06 +#* +#* Autor: Bogdanovic Theodor +#* Contact: t.bogdanovic@hotmail.com +#* +#* License: GPLv3 +#* +#************************************************************************************** +#************************************************************************************** +#* Further explanations: This source code is under the license specified by the +#* Autor above. Core components or other packages are still +#* in source code form, under the license specified by the +#* respective author. +#* +#************************************************************************************** + +[Unit] +Description=KVM Store Server +Wants=network.target network-online.target autofs.service +After=network.target network-online.target autofs.service + +[Service] +Type=simple +User=kvmstoreserver +ExecStart=/home/kvmstoreserver/kvmstoreserver/bin/kvmstoreserver -config /home/kvmstoreserver/kvmstoreserver/etc/kvmstoreserver.conf +LimitNOFILE=500000 +LimitNPROC=500000 +Nice=-10 +PIDFile=/var/run/kvmstoreserver.pid + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/kvmstoreserver_installer/data/utils/inject_disk b/kvmstoreserver_installer/data/utils/inject_disk new file mode 100644 index 0000000..052c548 Binary files /dev/null and b/kvmstoreserver_installer/data/utils/inject_disk differ diff --git a/kvmstoreserver_installer/kvmss-installer.sh b/kvmstoreserver_installer/kvmss-installer.sh new file mode 100755 index 0000000..e11ab59 --- /dev/null +++ b/kvmstoreserver_installer/kvmss-installer.sh @@ -0,0 +1,301 @@ +#!/usr/bin/env bash + +#************************************************************************************** +#* +#* Project: kvmstoreserver +#* File name: kvmss-installer.sh +#* Version: 1.0.0 +#* Date: 2018-02-06 +#* +#* Autor: Bogdanovic Theodor +#* Contact: t.bogdanovic@hotmail.com +#* +#* License: GPLv3 +#* +#************************************************************************************** +#************************************************************************************** +#* Copyright 2018 Bogdanovic Theodor +#* +#* This file is part of kvmstoreserver. +#* +#* kvmstoreserver is free software: you can redistribute it and/or modify +#* it under the terms of the GNU General Public License as published by +#* the Free Software Foundation, either version 3 of the License, or +#* (at your option) any later version. +#* +#* kvmstoreserver is distributed in the hope that it will be useful, +#* but WITHOUT ANY WARRANTY; without even the implied warranty of +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#* GNU General Public License for more details. +#* +#* You should have received a copy of the GNU General Public License +#* along with kvmstoreserver. If not, see . +#**************************************************************************************/ +#************************************************************************************** +#* Further explanations: This source code is under the license specified by the +#* Autor above. Core components or other packages are still +#* in source code form, under the license specified by the +#* respective author. +#* +#************************************************************************************** + +### Variables ### + +IP_OR_DOMNAME="" +INSTALL_ROOT="/home/kvmstoreserver/kvmstoreserver" +USERNAME="kvmstoreserver" +USER_PASSWD="" +SELECT_ANSWER="" +EXIST_AN_INSTALLATION=100 + +### Functions ### + +function window::if_user_root() +{ + if [ `id -u` -ne 0 ] + then + whiptail --title "KVM Store Server Installer" --msgbox "You need root rights to run this installer. Please try again with sudo kvmss-installer" 10 70 + exit 1 + fi +} + +function window::run_installer() +{ + local kind=$1 + + if [ $kind == "install" ] + then + if (! whiptail --title "KVM Store Server Installer" --yesno "Do you want to start installing of the KVM Store Server" 8 70) + then + exit 0 + fi + elif [ $kind == "delete" ] + then + if (! whiptail --title "KVM Store Server Installer" --yesno "Do you want to start deletion of the KVM Store Server - Attention, this will also erase the stored data!" 8 70) + then + exit 0 + fi + else + exit 1 + fi +} + +function window::enter_ip_or_name() +{ + name=$(whiptail --inputbox "Please enter the IP address of your computer on which the KVM Store Server should listen, alternatively you can also use the valid domain name of your computer - Example -> 192.168.0.5 or my-computer.my-domain.com You can also leave this field blank, then the server listens to all interfaces - THIS CONFIGURATION IS NOT RECOMMENDED!" 12 90 --title "KVM Store Server Installer" 3>&1 1>&2 2>&3) + + answer=$? + if [ $answer = 0 ]; then + IP_OR_DOMNAME=$name + else + exit 0 + fi +} + +function core::exist_an_installation() +{ + if [ -d $INSTALL_ROOT ] + then + EXIST_AN_INSTALLATION=1 + else + EXIST_AN_INSTALLATION=0 + fi +} + +function window::enter_passwd() +{ + for (( ; ; )) + do + passwd_1=$(whiptail --passwordbox "Please enter a password for the new linux user kvmstoreserver - Please do not use backslash" 8 60 --title "KVM Store Server Installer" 3>&1 1>&2 2>&3) + + answer=$? + [ $answer != 0 ] && exit 0 + + passwd_2=$(whiptail --passwordbox "Please enter the password again" 8 60 --title "KVM Store Server Installer" 3>&1 1>&2 2>&3) + + answer=$? + if [ $answer = 0 ] + then + if [ ${passwd_1} == ${passwd_2} ] && [ ! -z ${passwd_2} ] + then + USER_PASSWD=$passwd_2 + break + else + whiptail --title "KVM Store Server Installer" --msgbox "The passwords do not match. Try again" 8 45 + continue + fi + else + exit 0 + fi + done +} + +function core::create_kvmss_user() +{ + sudo useradd $USERNAME -m + echo -e "$USER_PASSWD\n$USER_PASSWD\n" | sudo passwd $USERNAME +} + +function core::create_folder_struct() +{ + sudo mkdir $INSTALL_ROOT + sudo mkdir $INSTALL_ROOT/bin + sudo mkdir $INSTALL_ROOT/etc + sudo mkdir $INSTALL_ROOT/warehouse + sudo mkdir $INSTALL_ROOT/utils + sudo mkdir $INSTALL_ROOT/var + sudo mkdir $INSTALL_ROOT/var/log +} + +function core::change_rights() +{ + sudo chmod u+rw $INSTALL_ROOT/var/log + sudo chmod g+rw $INSTALL_ROOT/var/log + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/var/log + + sudo chmod u+rw $INSTALL_ROOT/var + sudo chmod g+rw $INSTALL_ROOT/var + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/var + + sudo chmod u+rw $INSTALL_ROOT/warehouse + sudo chmod g+rw $INSTALL_ROOT/warehouse + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/warehouse + + sudo chmod u+rw $INSTALL_ROOT/utils + sudo chmod g+rw $INSTALL_ROOT/utils + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/utils + + sudo chmod u+rw $INSTALL_ROOT/etc + sudo chmod g+rw $INSTALL_ROOT/etc + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/etc + + sudo chmod u+rw $INSTALL_ROOT/bin + sudo chmod g+rw $INSTALL_ROOT/bin + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/bin + + sudo chmod u+rwx $INSTALL_ROOT/utils/inject_disk + sudo chmod g+rwx $INSTALL_ROOT/utils/inject_disk + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/utils/inject_disk + + sudo chmod u+rwx $INSTALL_ROOT/bin/kvmstoreserver + sudo chmod g+rwx $INSTALL_ROOT/bin/kvmstoreserver + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/bin/kvmstoreserver + + sudo chmod u+rw $INSTALL_ROOT/etc/kvmstoreserver.conf + sudo chmod g+rw $INSTALL_ROOT/etc/kvmstoreserver.conf + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT/etc/kvmstoreserver.conf + + sudo chmod u+rw $INSTALL_ROOT + sudo chmod g+rw $INSTALL_ROOT + sudo chown $USERNAME:$USERNAME $INSTALL_ROOT +} + +function core::copy_files() +{ + sudo cp ./data/bin/kvmstoreserver $INSTALL_ROOT/bin/kvmstoreserver + sudo cp ./data/utils/inject_disk $INSTALL_ROOT/utils/inject_disk + sudo cp ./data/etc/kvmstoreserver.conf $INSTALL_ROOT/etc/kvmstoreserver.conf + sudo cp ./data/init/kvmstoreserver.service /etc/systemd/system/kvmstoreserver.service +} + +function core::install_and_run_daemon() +{ + sudo systemctl daemon-reload + sudo systemctl start kvmstoreserver.service + sudo systemctl enable kvmstoreserver.service +} + +function core::replace_server_name() +{ + sudo sed -i -e "s/http_hostname = /http_hostname = $IP_OR_DOMNAME/g" $INSTALL_ROOT/etc/kvmstoreserver.conf +} + +function window::select_action() +{ + + if [ $EXIST_AN_INSTALLATION = 0 ] + then + selection=$(whiptail --title "KVM Store Server Installer" --menu "Choose an option" 9 70 2 \ + "Install" "Installs the KVM Store Server on the hard disk" 3>&1 1>&2 2>&3) + + answer=$? + [ $answer != 0 ] && exit 0 + elif [ $EXIST_AN_INSTALLATION = 1 ] + then + selection=$(whiptail --title "KVM Store Server Installer" --menu "Choose an option" 9 70 2 \ + "Remove " "Delete the KVM Store Server completely from the hard disk" 3>&1 1>&2 2>&3) + answer=$? + [ $answer != 0 ] && exit 0 + fi + + SELECT_ANSWER=$selection +} + +function window::finish_text() +{ + local kind=$1 + + if [ $kind == "install" ] + then + if (whiptail --title "KVM Store Server Installer" --msgbox "The installation is complete, the server is now running - The configuration file can be found at /home/kvmstoreserver/kvmstoreserver/etc/kvmstoreserver.conf. There you can make all relevant settings. After a change in the configuration file, you may need to run - sudo systemctl restart kvmstoreserver.service - in the console" 13 90) + then + exit 0 + fi + elif [ $kind == "delete" ] + then + if (whiptail --title "KVM Store Server Installer" --msgbox "The KVM Store Server is completlly deleted from your Harddisk" 8 70) + then + exit 0 + fi + fi +} + +function main::install() +{ + window::run_installer "install" + window::enter_ip_or_name + window::enter_passwd + + { + echo XXX && echo 10 && echo "Creating kvmstoreserver user" && echo XXX && core::create_kvmss_user > /dev/null 2>&1 + echo XXX && echo 20 && echo "Creating folder structure" && echo XXX && core::create_folder_struct > /dev/null 2>&1 + echo XXX && echo 40 && echo "Copy files" && echo XXX && core::copy_files > /dev/null 2>&1 + echo XXX && echo 50 && echo "Configure config file" && echo XXX && core::replace_server_name > /dev/null 2>&1 + echo XXX && echo 70 && echo "Changing rights" && echo XXX && core::change_rights > /dev/null 2>&1 + echo XXX && echo 100 && echo "Install an run kvmstoreserver daemon" && echo XXX && core::install_and_run_daemon > /dev/null 2>&1 + } | whiptail --title "Please wait KVM Store Server will be installed" --gauge "Start" 6 60 0 + + window::finish_text "install" +} + +function main::remove() +{ + window::run_installer "delete" + + { + echo XXX && echo 10 && echo "Killing all processes of user kvmstoreserver" && echo XXX && sudo killall --user $USERNAME > /dev/null 2>&1 + echo XXX && echo 20 && echo "Stopping kvmstoreserver service" && echo XXX && sudo systemctl stop kvmstoreserver.service -f > /dev/null 2>&1 + echo XXX && echo 40 && echo "Deactivating kvmstoreserver service" && echo XXX && sudo systemctl disable kvmstoreserver.service -f > /dev/null 2>&1 + echo XXX && echo 50 && echo "Removing kvmstoreserver service" && echo XXX && sudo rm /etc/systemd/system/kvmstoreserver.service > /dev/null 2>&1 + echo XXX && echo 80 && echo "Reloading Systemd init system" && echo XXXsudo systemctl daemon-reload > /dev/null 2>&1 + + echo XXX && echo 100 && echo "Deleting kvmstoreserver user and DATA" && echo XXX && sudo deluser $USERNAME --remove-home > /dev/null 2>&1 + } | whiptail --title "Please wait, KVM Store Server will be deleted" --gauge "Start" 6 60 0 + + window::finish_text "delete" +} + +### MAIN ### + +window::if_user_root +core::exist_an_installation +window::select_action + +case $selection in + "Install") main::install + ;; + "Remove ") main::remove + ;; + *) echo "Unknown" + ;; +esac diff --git a/kvmstoreserver_solution/etc/kvmstoreserver.conf b/kvmstoreserver_solution/etc/kvmstoreserver.conf new file mode 100755 index 0000000..bfe4a4b --- /dev/null +++ b/kvmstoreserver_solution/etc/kvmstoreserver.conf @@ -0,0 +1,55 @@ +#****************************************************************************** +#* storeserver main config file +#****************************************************************************** + +#****************************************************************************** +#* The kvmstoreserver was compiled with the configPoller extension. This means +#* that changes to this config file can be captured after 60 seconds and +#* loaded at runtime of the kvmstoreserver. Not all of the parameters listed +#* below can be updated at runtime. Parameters with the comment label DYNAMIC +#* can be updated at runtime. Parameters with the label STATIC did not belong. +#* +#* Caution when updating DYNAMIC parameters. +#* In case of incorrect entries, the kvmstoreserver can crash! +#* +#****************************************************************************** + + +###################### General Server settings ################################ + +# DINAMIC +storage_target = /kvmstoreserver_solution/var/warehouse + +# DINAMIC +serde_driver = filesystem + +# All log file parameters -> STATIC +default_log_file = /kvmstoreserver_solution/var/log/storeserver.log +log_max_size_mb = 100 +log_max_age_days = 30 +log_write_to_console = true + + +######################### HTTP Server settings ############################### + +# All HTTP Server Settings -> STATIC +http_hostname = +http_port = 3344 +read_header_timeout = 30 +read_timeout = 30 +write_timeout = 30 +tcp_idle_timeout_millsec = 100 + +########################### Http Route settings ############################## +### Attention, the maximum path length per route is reduced to 1. Longer paths, +### such as /controller/add/ are not allowed and cause errors + +### All routes that work with JSON documents must always have an end slash in +### the name such as /add"/" + +# All Controller parameter -> STATIC +ctrl_add_path = /add/ +ctrl_get_path = /get/ +ctrl_del_path = /del/ +ctrl_tree_path = /tree +ctrl_version_path = /version \ No newline at end of file diff --git a/kvmstoreserver_solution/etc/kvmstoreserver_test.conf b/kvmstoreserver_solution/etc/kvmstoreserver_test.conf new file mode 100755 index 0000000..d04f7df --- /dev/null +++ b/kvmstoreserver_solution/etc/kvmstoreserver_test.conf @@ -0,0 +1,55 @@ +#****************************************************************************** +#* storeserver main config file +#****************************************************************************** + +#****************************************************************************** +#* The kvmstoreserver was compiled with the configPoller extension. This means +#* that changes to this config file can be captured after 60 seconds and +#* loaded at runtime of the kvmstoreserver. Not all of the parameters listed +#* below can be updated at runtime. Parameters with the comment label DYNAMIC +#* can be updated at runtime. Parameters with the label STATIC did not belong. +#* +#* Caution when updating DYNAMIC parameters. +#* In case of incorrect entries, the kvmstoreserver can crash! +#* +#****************************************************************************** + + +###################### General Server settings ################################ + +# DINAMIC +storage_target = /kvmstoreserver_solution/var/warehouse_test + +# DINAMIC +serde_driver = filesystem + +# All log file parameters -> STATIC +default_log_file = /kvmstoreserver_solution/var/log/storeserver_test.log +log_max_size_mb = 100 +log_max_age_days = 30 +log_write_to_console = true + + +######################### HTTP Server settings ############################### + +# All HTTP Server Settings -> STATIC +http_hostname = +http_port = 3345 +read_header_timeout = 30 +read_timeout = 30 +write_timeout = 30 +tcp_idle_timeout_millsec = 100 + +########################### Http Route settings ############################## +### Attention, the maximum path length per route is reduced to 1. Longer paths, +### such as /controller/add/ are not allowed and cause errors + +### All routes that work with JSON documents must always have an end slash in +### the name such as /add"/" + +# All Controller parameter -> STATIC +ctrl_add_path = /add/ +ctrl_get_path = /get/ +ctrl_del_path = /del/ +ctrl_tree_path = /tree +ctrl_version_path = /version \ No newline at end of file diff --git a/kvmstoreserver_solution/src/essentials/controlEnums.go b/kvmstoreserver_solution/src/essentials/controlEnums.go new file mode 100755 index 0000000..7a6bb18 --- /dev/null +++ b/kvmstoreserver_solution/src/essentials/controlEnums.go @@ -0,0 +1,61 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: controlEnums.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package essentials offers various control elements that can be used by all +// components. In this way, enums are formed in Go +package essentials + +// Control wrapps the type unit8 +type Control uint8 + +const ( + // DoPanic is used to signal that a panic is necessary + DoPanic Control = iota + + // DontPanic is used to signal that a panic is not necessary + DontPanic + + // Save is used to signal that something needs to be saved + Save + + // Delete is used to signal that something needs to be deleted + Delete + + // Load is used to signal that something needs to be loaded + Load +) diff --git a/kvmstoreserver_solution/src/essentials/injectJsonRespHeader.go b/kvmstoreserver_solution/src/essentials/injectJsonRespHeader.go new file mode 100755 index 0000000..e9beb4c --- /dev/null +++ b/kvmstoreserver_solution/src/essentials/injectJsonRespHeader.go @@ -0,0 +1,58 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: injectJsonRespHeader.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package essentials contains components that offer various functionalities for +// different purposes. Everyone can use these functionalities +package essentials + +import ( + "net/http" +) + +//***************************************************************************** +//* +//* Public Finctions +//* +//***************************************************************************** + +// InjectJSONTypeToHeader Injected in the response header the key value pair +// Content-Type = application/json +func InjectJSONTypeToHeader(writer http.ResponseWriter) { + + writer.Header().Set("Content-Type", "application/json") +} diff --git a/kvmstoreserver_solution/src/essentials/trimUrlKeyName.go b/kvmstoreserver_solution/src/essentials/trimUrlKeyName.go new file mode 100755 index 0000000..3f94c65 --- /dev/null +++ b/kvmstoreserver_solution/src/essentials/trimUrlKeyName.go @@ -0,0 +1,57 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: trimUrlKeyName.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package essentials + +import ( + "strings" +) + +//***************************************************************************** +//* +//* Public Functions: +//* +//***************************************************************************** + +// CutKeyFromURL cuts the key name out of the URL. This function only works if +// the corresponding middleware is in front of it and performs a preliminary +// check +func CutKeyFromURL(s string) string { + + return strings.Split(strings.Split(s, "/")[2], "?")[0] +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/main.go b/kvmstoreserver_solution/src/kvmstoreserver/main.go new file mode 100755 index 0000000..1a16de8 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/main.go @@ -0,0 +1,52 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: main.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package main contains the start sequence of the kvmstoreserver. After +// initializing the start method (this is a wrapper to the HTTP instance), the +// HTTP server prevents mehtode from causing it to jump to the end. The wait +// method intercepts the main end until the function gracefulShutdown() is done +package main + +func main() { + + kvmstoreserver := newAppServer(false, "") + + kvmstoreserver.start() + + kvmstoreserver.wait() +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/stage0.go b/kvmstoreserver_solution/src/kvmstoreserver/stage0.go new file mode 100755 index 0000000..5b9d452 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/stage0.go @@ -0,0 +1,157 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: stage0.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "flag" + "fmt" + "os" + "os/signal" + "strings" + "syscall" + conf "utils/configMap" + "utils/configPoller" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Structure: appServer +//* +//***************************************************************************** + +// appServer is a unit-like structure. it is empty and serves +// only as a method wrapper for the http instance +type appServer struct{} + +//******************** Methods ************************************************ + +// start starts the HTTP instance in stage0_ext3 +func (slf *appServer) start() { + + log.Infof("Starting HTTP frontend - kvmstoreserver is online and listen on http://%v:%v", + conf.GetStringOf("http_hostname"), conf.GetStringOf("http_port")) + + httpFrontend.start() +} + +// wait activated when the HTTP server goes off. prevents the +// end before the graceful shutdown procedure is finished +func (slf *appServer) wait() { shutdown.wg.Wait() } + +//***************************************************************************** +//* +//* storeserver startup initiator +//* +//***************************************************************************** + +// newAppServer creates a new wrapper instance and initialize +// all components in the following order: +// +// 1.) set configMap +// 2.) set configPoller +// 3.) set logrjack log engine +// 4.) init (load) Btree +// 5.) init Middleware Chains +// 6.) init a new HTTP instance +// 7.) init a separate goroutine for shutdown signals (only sigint and sigterm) +func newAppServer(testMode bool, overridePath string) *appServer { + + if testMode { + conf.Settings(overridePath) + log.Infof("Starting storeserver in test mode with a different config -> %v", + overridePath) + } else { + conf.Settings(pathFromCmd()) + } + + // Register config reader in config poller + configPoller.RegisterReaders(60, conf.GetConfigMapRef()) + + log.Setup(log.Settings{ + Filename: conf.GetStringOf("default_log_file"), + MaxSizeMB: (int)(conf.GetInt32Of("log_max_size_mb")), + MaxAgeDays: (int)(conf.GetInt32Of("log_max_age_days")), + WriteStdout: conf.GetBoolOf("log_write_to_console"), + }) + + log.Info( + "Start config poller in a seperate goroutine with a polling interval of -> 60 Seconds", + ) + + log.Info("******************** Initialze start procedure ********************") + initializeBtree() + + log.Info("Initialize Middleware components and final handlers") + initializeMiddleware() + + log.Info("Initialize a new HTTP server instance") + initializeHTTPInstance() + + initializeShutdownWatcher() + signal.Notify(shutdown.signalChan, syscall.SIGINT, syscall.SIGTERM) + go shutdown.captureSignal() + + var as appServer + + return &as +} + +//***************************************************************************** +//* +//* Private Methods +//* +//***************************************************************************** + +// Parse command line args if the param -config is set +func pathFromCmd() string { + + pathToConfig := flag.String("config", "", + "The path to the main configuration file") + flag.Parse() + + trimmedConfigPath := strings.Trim(*pathToConfig, " ") + if trimmedConfigPath == "" { + fmt.Println("Missing path to config file -> -config=") + os.Exit(-1) + } + + return *pathToConfig +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext1.go b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext1.go new file mode 100755 index 0000000..16f9893 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext1.go @@ -0,0 +1,232 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: stage0_ext1.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + * + **************************************************************************************/ + +package main + +import ( + "fmt" + "io/ioutil" + bth "kvmstoreserver_utils/bTreeHandling" + sh "kvmstoreserver_utils/serdeHandling" + "sort" + "strconv" + "strings" + "sync" + conf "utils/configMap" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Private Functions: Loader Functions +//* +//***************************************************************************** + +// initializeBtree initialize the Btree loader +func initializeBtree() { + + newNodeLoaderController().fillTree() +} + +//***************************************************************************** +//* +//* Structure: +//* +//***************************************************************************** + +// nodeLoaderController This structure serves as a node deserializer and +// loader. It synchronizes its own structure with an internal lock mechanism +type nodeLoaderController struct { + initBtree bth.IBtreeController + rootNodeID int + nodeListSlice []int + nodeListLenght int + nodeCounter int + lockController sync.Mutex + wg sync.WaitGroup +} + +//******************** Load Methods ******************************************* + +// fillTree this structure takes over the actual loading of the nodes into +// the tree. It executes the loading of the nodes in parallel (uncontrolled +// with up to 10000 goroutines or mapped 1:1 OS threads) +func (slf *nodeLoaderController) fillTree() { + + backend := sh.LoaderFactory() + + if slf.nodeListLenght == 0 && slf.rootNodeID == 0 { + log.Info("The backend storage was empty - Nothing loaded") + } else { + + newRootNode := bth.CreateContainerFromSource(backend(slf.rootNodeID)) + slf.initBtree.InsertContainer(newRootNode) + + log.Infof("The following node was loaded as root -> (ID: %v) | (Orig Key Name: %v)", + newRootNode.GetID(), newRootNode.GetOrigKeyName()) + + // Here is the parallel load of nodes. The WaitGroup is prepared in + // the Cotroller, but there were problems with using it in a FOR loop. + // On a file system level, this is not necessary. For future use with + // a DB, a chunk-based method must be implemented + for idx := 0; idx < slf.nodeListLenght; idx++ { + slf.wg.Add(1) + go deserialNode(slf, slf.nodeListSlice[idx]) + } + + // Wait until all routines are done + slf.wg.Wait() + + if slf.nodeCounter != slf.nodeListLenght { + log.Fatalf("Not all nodes could be deserialized (only: %v) - Start aborted", + slf.nodeCounter) + } + log.Infof("All nodes could be loaded | Loaded -> %v", + slf.nodeListLenght) + } + +} + +//***************************************************************************** + +//***************************************************************************** +//* +//* Public Fnctions +//* +//***************************************************************************** + +// newNodeLoaderController returns a prepared controller back +func newNodeLoaderController() *nodeLoaderController { + + var nodeLoader nodeLoaderController + + nodeLoader.initBtree = bth.NewBtree() + nodeLoader.nodeListSlice, nodeLoader.rootNodeID = getNodeListWithRoot() + nodeLoader.nodeListLenght = len(nodeLoader.nodeListSlice) + + return &nodeLoader +} + +//***************************************************************************** +//* +//* Private Functions: Helper Functions +//* +//***************************************************************************** + +// getSortedNodeList This function reads in the file names of the nodes and +// saves them in a slice. It also extracts the most suitable node as root node +func getNodeListWithRoot() ([]int, int) { + + var intList []int + var copyOfIntList []int + var rootNode int + + rawObjList, loadErr := ioutil.ReadDir(conf.GetStringOf("storage_target")) + if loadErr != nil { + panic("Can not load node files!") + } + + if len(rawObjList) > 0 { + for idx := 0; idx < len(rawObjList); idx++ { + rawName := strings.Split(rawObjList[idx].Name(), ".json")[0] + newInt64, err := strconv.ParseInt(rawName, 10, 64) + if err != nil { + errMsg := fmt.Sprintf("Corrupt file name -> (%v)", + rawObjList[idx].Name()) + panic(errMsg) + } + + newInt := int(newInt64) + intList = append(intList, newInt) + + } + copyOfIntList = make([]int, len(intList)) + + // Make a copy of the slice and sort it. This identifies the middle + // node, which serves as the root node. The list was then discarded + copy(copyOfIntList, intList) + sort.Ints(copyOfIntList) + + rootNodeIdx := len(copyOfIntList) / 2 + rootNode = copyOfIntList[rootNodeIdx] + + if rootNodeIdx == 0 && len(rawObjList) == 1 { + return make([]int, 0), rootNode + } + + var rootDelIdx int + + if rootNodeIdx > 0 { + for index, id := range intList { + if id == rootNode { + rootDelIdx = index + } + } + + intList = append(intList[:rootDelIdx], intList[rootDelIdx+1:]...) + } + } else { + return make([]int, 0), rootNode + } + + return intList, rootNode +} + +// deserialNode function is often executed as a standalone goutout +func deserialNode(ncl *nodeLoaderController, curruentListIdx int) { + + defer func() { + err := recover() + if err != nil { + log.Warnf("Problem by parallel deserialization -> (ID: %v) | (Orig Err: %v)", + curruentListIdx, err) + } + }() + + backend := sh.LoaderFactory() + + ncl.lockController.Lock() + + ncl.initBtree.InsertContainer(bth.CreateContainerFromSource(backend(curruentListIdx))) + ncl.nodeCounter++ + ncl.wg.Add(-1) + + ncl.lockController.Unlock() +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext2.go b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext2.go new file mode 100755 index 0000000..f425fd7 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext2.go @@ -0,0 +1,138 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: stage0_ext2.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + fh "kvmstoreserver_utils/HttpHandlers/finalHandlers" + mf "kvmstoreserver_utils/HttpHandlers/middlewareFunctions" + "net/http" + fcb "utils/Middleware/functionChainBuilder" + conf "utils/configMap" + "versionInfo" + + log "github.com/judwhite/logrjack" +) + +// Here, middleware chian containers can be formed and the corresponding routes +// defined. A convention valid in this file requires setting log entries for +// loading containers and routes +func initializeMiddleware() { + + //***************************************************************************** + //* + //* Create and set Middleware components and final handlers + //* + //***************************************************************************** + + // Setup controller /add/ + ctrlAddChain := fcb.NewChainConatainer(). + RegisterFunctions(mf.MWareInOutLogger, mf.MWareIfMethodPost, mf.MWareCheckKeyInURL). + SetFinalHandler(fh.AddFinalHandler) + + log.Infof("Initialize chain container for route -> %v", + conf.GetStringOf("ctrl_add_path")) + + // Setup controller /get/ + ctrlGetChain := fcb.NewChainConatainer(). + RegisterFunctions(mf.MWareInOutLogger, mf.MWareIfMethodGet, mf.MWareCheckKeyInURL, mf.MwareCheckParamIntegrity). + SetFinalHandler(fh.GetFinalHandler) + + log.Infof("Initialize chain container for route -> %v", + conf.GetStringOf("ctrl_get_path")) + + // Setup controller /del/ + ctrlDelChain := fcb.NewChainConatainer(). + RegisterFunctions(mf.MWareInOutLogger, mf.MWareIfMethodDelete, mf.MWareCheckKeyInURL). + SetFinalHandler(fh.DelFinalHandler) + + log.Infof("Initialize chain container for route -> %v", + conf.GetStringOf("ctrl_del_path")) + + // Setup controller /tree + ctrlTreeChain := fcb.NewChainConatainer(). + RegisterFunctions(mf.MWareInOutLogger, mf.MWareIfMethodGet). + SetFinalHandler(fh.TreeFinalHandler) + + log.Infof("Initialize chain container for route -> %v", + conf.GetStringOf("ctrl_tree_path")) + + // Setup controller /tree + ctrlVersionChain := fcb.NewChainConatainer(). + RegisterFunctions(mf.MWareInOutLogger, mf.MWareIfMethodGet). + SetFinalHandler(versionInfo.VerInfoFinalHandler) + + log.Infof("Initialize chain container for route -> %v", + conf.GetStringOf("ctrl_version_path")) + + //***************************************************************************** + //* + //* Configure Routes + //* + //***************************************************************************** + + // Configure ROUTE for controller /add/ + http.Handle(conf.GetStringOf("ctrl_add_path"), ctrlAddChain.RunChain()) + + log.Infof("Set controller into route -> %v", + conf.GetStringOf("ctrl_add_path")) + + // Configure ROUTE for controller /get/ + http.Handle(conf.GetStringOf("ctrl_get_path"), ctrlGetChain.RunChain()) + + log.Infof("Set controller into route -> %v", + conf.GetStringOf("ctrl_get_path")) + + // Configure ROUTE for controller /del/ + http.Handle(conf.GetStringOf("ctrl_del_path"), ctrlDelChain.RunChain()) + + log.Infof("Set controller into route -> %v", + conf.GetStringOf("ctrl_del_path")) + + // Configure ROUTE for controller /tree + http.Handle(conf.GetStringOf("ctrl_tree_path"), ctrlTreeChain.RunChain()) + + log.Infof("Set controller into route -> %v", + conf.GetStringOf("ctrl_tree_path")) + + // Configure ROUTE for controller /tree + http.Handle(conf.GetStringOf("ctrl_version_path"), ctrlVersionChain.RunChain()) + + log.Infof("Set controller into route -> %v", + conf.GetStringOf("ctrl_version_path")) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext3.go b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext3.go new file mode 100755 index 0000000..b234426 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext3.go @@ -0,0 +1,97 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: stage0_ext3.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "fmt" + "net/http" + "time" + conf "utils/configMap" +) + +//***************************************************************************** +//* +//* Private Functions: Loader Functions +//* +//***************************************************************************** + +// Here a new HTTP server instance is formed. It runs on its own structure, so +// that functionalities of the Go HTTP package can be abstracted using own +// methods +func initializeHTTPInstance() { + + httpFrontend.server = http.Server{ + Addr: conf.GetStringOf("http_hostname") + ":" + conf.GetStringOf("http_port"), + ReadHeaderTimeout: time.Second * time.Duration(conf.GetInt32Of("read_header_timeout")), + ReadTimeout: time.Second * time.Duration(conf.GetInt32Of("read_timeout")), + WriteTimeout: time.Second * time.Duration(conf.GetInt32Of("write_timeout")), + IdleTimeout: time.Millisecond * time.Duration(conf.GetInt32Of("tcp_idle_timeout_millsec")), + } +} + +//***************************************************************************** +//* +//* Variable declarations +//* +//***************************************************************************** + +var httpFrontend httpServer + +//***************************************************************************** +//* +//* Structure: httpServer +//* +//***************************************************************************** + +// httpServer ... +type httpServer struct { + server http.Server +} + +//******************** Methods ************************************************ + +func (slf *httpServer) start() { + + err := slf.server.ListenAndServe() + if err != nil { + fmt.Println("The HTTP component is stopped") + } +} + +func (slf *httpServer) stop() { slf.server.Close() } diff --git a/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext4.go b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext4.go new file mode 100755 index 0000000..accc3b8 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/stage0_ext4.go @@ -0,0 +1,108 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: stage0_ext4.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "fmt" + "os" + "sync" + "syscall" + "time" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Private Functions: Loader Functions +//* +//***************************************************************************** + +// This controller controls the removal of OS signals. So a ctrl + c or SIGTERM +// can be intercepted and a clean shutdown initiated +func initializeShutdownWatcher() { + + shutdown = &shutdownController{signalChan: make(chan os.Signal, 1)} +} + +//***************************************************************************** +//* +//* Variable declarations +//* +//***************************************************************************** + +var shutdown *shutdownController + +//***************************************************************************** +//* +//* Struct: shutdownCotroller +//* +//***************************************************************************** + +// shutdownController ... +type shutdownController struct { + signalChan chan os.Signal + wg sync.WaitGroup +} + +//******************** Methods ************************************************ + +// This method is started from the outside as goroutine +func (slf *shutdownController) captureSignal() { + + sig := <-slf.signalChan + if sig == syscall.SIGINT || + sig == syscall.SIGTERM { + slf.gracefulShutdown() + } +} + +func (slf *shutdownController) gracefulShutdown() { + + slf.wg.Add(1) + httpFrontend.stop() + + fmt.Println("Start graceful shutdown procedure - Please wait...") + log.Info("Started graceful shutdown procedure") + time.Sleep(time.Second * 5) + fmt.Println("The appserver is down - Bye :)") + log.Info("The server ist down") + + slf.wg.Done() +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_001_test.go b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_001_test.go new file mode 100755 index 0000000..59c0c37 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_001_test.go @@ -0,0 +1,101 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: testCaseRef_4_3_001_test.go + * Version: 1.0.0 + * Date: 2018-01-12 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "testing" +) + +// Test4_3_001_test tests the middleware, which should intercept wrong HTTP methods. +// Here are the following tests: +// +// - Try using Add with POST (Must work) +// - Try using Add with DELETE (Error message expected) +// - Try using Add with GET (Error message expected) +// +// - Try using Get with GET (Must work) +// - Try using Get with DELETE (Error message expected) +// - Try using Get with POST (Error message expected) +// +// - Try using Del with DELETE (Must work) +// - Try using Del with POST (Error message expected) +// - Try using Del with GET (Error message expected) +func Test4_3_001_test(t *testing.T) { + + // Create test data + tests := []struct { + name string + keySeqNbr int + revNbr int + cliAction clientAction + httpMeth string + wantedStatusCode int + }{ + // Test sequence 1 + {name: "Test 1_1: Try to insert entry (Controller /add/ | Method POST)", keySeqNbr: 100, revNbr: 0, cliAction: actionAdd, httpMeth: POST, wantedStatusCode: 201}, + {name: "Test 1_2: Try to insert entry (Controller /add/ | Method DELETE)", keySeqNbr: 100, revNbr: 0, cliAction: actionAdd, httpMeth: DELETE, wantedStatusCode: 405}, + {name: "Test 1_3: Try to insert entry (Controller /add/ | Method GET)", keySeqNbr: 100, revNbr: 0, cliAction: actionAdd, httpMeth: GET, wantedStatusCode: 405}, + // Test sequence 2 + {name: "Test 2_1: Try to get entry (Controller /get/ | Method GET)", keySeqNbr: 100, revNbr: 0, cliAction: actionGet, httpMeth: GET, wantedStatusCode: 200}, + {name: "Test 2_2: Try to get entry (Controller /get/ | Method DELETE)", keySeqNbr: 100, revNbr: 0, cliAction: actionGet, httpMeth: DELETE, wantedStatusCode: 405}, + {name: "Test 2_3: Try to get entry (Controller /get/ | Method POST)", keySeqNbr: 100, revNbr: 0, cliAction: actionGet, httpMeth: POST, wantedStatusCode: 405}, + // Test sequence 3 + {name: "Test 3_1: Try to delete entry (Controller /del/ | Method DELETE)", keySeqNbr: 100, revNbr: 0, cliAction: actionDel, httpMeth: DELETE, wantedStatusCode: 200}, + {name: "Test 3_2: Try to delete entry (Controller /del/ | Method POST)", keySeqNbr: 100, revNbr: 0, cliAction: actionDel, httpMeth: POST, wantedStatusCode: 405}, + {name: "Test 3_3: Try to delete entry (Controller /del/ | Method GET)", keySeqNbr: 100, revNbr: 0, cliAction: actionDel, httpMeth: GET, wantedStatusCode: 405}, + } + + // Start a test server in a separate gourutine + runKvmssTestInstance() + + // Clean up the environment (if there are remnants of the last test) + testClient(tests[0].keySeqNbr, tests[0].revNbr, actionDel, DELETE, "") + + // Execute the test series + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := testClient(tt.keySeqNbr, tt.revNbr, tt.cliAction, tt.httpMeth, ""); got.StatusCode != tt.wantedStatusCode { + t.Errorf("Start testClient() (Client Test Desc.: HTTP Method allowed?) = %v, want %v", got.StatusCode, tt.wantedStatusCode) + } + }) + } + + // Post job: Clean up the environment + testClient(tests[0].keySeqNbr, tests[0].revNbr, actionDel, DELETE, "") +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_005_2_test.go b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_005_2_test.go new file mode 100755 index 0000000..eb88018 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_005_2_test.go @@ -0,0 +1,216 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: testCaseRef_4_3_005_2_test.go + * Version: 1.0.0 + * Date: 2018-01-12 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" +) + +// Test4_3_005_2_test contains several individual tests. The detailed +// descriptions of the tests can be found as comments in the tests themselves +func Test4_3_005_2_test(t *testing.T) { + + // Create test struct for the test data + type innerStruct []struct { + name string + keySeqNbr int + revNbr int + cliAction clientAction + httpMeth string + paramExt string + } + tests := map[int]innerStruct{} + tests = make(map[int]innerStruct, 0) + + // Create test data + tests[0] = innerStruct{ + // Insert sequence 1 + {name: "Test 1_1: Try to insert entry first time (Controller /get/ | Method Get)", keySeqNbr: 501, revNbr: 0, cliAction: actionGet, httpMeth: GET, paramExt: "?rev"}, + {name: "Test 1_2: Try to insert entry second time (Controller /get/ | Method Get)", keySeqNbr: 501, revNbr: 1, cliAction: actionGet, httpMeth: GET, paramExt: "?search"}, + {name: "Test 1_3: Try to insert entry third time (Controller /get/ | Method Get)", keySeqNbr: 501, revNbr: 2, cliAction: actionGet, httpMeth: GET, paramExt: "?search=rev_nbr"}, + } + tests[1] = innerStruct{ + // Insert sequence 2 + {name: "Test 2_1: Try to insert entry first time (Controller /get/ | Method Get)", keySeqNbr: 502, revNbr: 0, cliAction: actionGet, httpMeth: GET, paramExt: "?search&rev"}, + {name: "Test 2_2: Try to insert entry second time (Controller /get/ | Method Get)", keySeqNbr: 502, revNbr: 1, cliAction: actionGet, httpMeth: GET, paramExt: "?rev=1&search=rev_nbr"}, + {name: "Test 2_3: Try to insert entry third time (Controller /get/ | Method POST)", keySeqNbr: 502, revNbr: 2, cliAction: actionGet, httpMeth: GET}, + } + tests[2] = innerStruct{ + // Insert sequence 3 + {name: "Test 3_1: Try to insert entry first time (Controller /get/ | Method Get)", keySeqNbr: 503, revNbr: 0, cliAction: actionGet, httpMeth: GET, paramExt: "?search_wrong=rev_nbr"}, + {name: "Test 3_2: Try to insert entry second time (Controller /get/ | Method Get)", keySeqNbr: 503, revNbr: 1, cliAction: actionGet, httpMeth: GET}, + {name: "Test 3_3: Try to insert entry third time (Controller /get/ | Method Get)", keySeqNbr: 503, revNbr: 2, cliAction: actionGet, httpMeth: GET}, + } + + // Start a test server in a separate gourutine + runKvmssTestInstance() + + // Clean up the environment (if there are remnants of the last test) + testClient(tests[0][0].keySeqNbr, tests[0][0].revNbr, actionDel, DELETE, "") + testClient(tests[1][0].keySeqNbr, tests[1][0].revNbr, actionDel, DELETE, "") + testClient(tests[2][0].keySeqNbr, tests[2][0].revNbr, actionDel, DELETE, "") + + // Insert test data into kvmstoreserver + for _, outer := range tests { + for _, inner := range outer { + testClient(inner.keySeqNbr, inner.revNbr, actionAdd, POST, "") + } + } + + // Test 1: Try to get the JSON field RevNbr from key 1 revision 2 + // (Expected: Int 2 && Status code 200) + { + testLine := &tests[0][2] + got := testClient(testLine.keySeqNbr, testLine.revNbr, testLine.cliAction, testLine.httpMeth, testLine.paramExt) + ressult, _, resultStatus := parseBodyRevAndSearch(got) + if ressult != 2 || resultStatus != 200 { + t.Errorf("Start testClient() (%v) = %v | Status: %v, want %v | Status: %v", testLine, ressult, resultStatus, 2, 200) + } + } + + // Test 2: Try to get the JSON field RevNbr from key 2 revision 1 + // (Expected: Int 1 && Status code 200) + { + testLine := &tests[1][1] + got := testClient(testLine.keySeqNbr, testLine.revNbr, testLine.cliAction, testLine.httpMeth, testLine.paramExt) + ressult, _, resultStatus := parseBodyRevAndSearch(got) + if ressult != 1 || resultStatus != 200 { + t.Errorf("Start testClient() (%v) = %v | Status: %v, want %v | Status: %v", testLine.name, ressult, resultStatus, 1, 200) + } + } + + // Test 3: Try to get the JSON field RevNbr from key 3 revision 0 + // The http parameter search is misspelled + // (This test also applies to the parameter rev {Equivalent Implementation}) + // (Expected: Status code 400) + { + testLine := &tests[2][0] + got := testClient(testLine.keySeqNbr, testLine.revNbr, testLine.cliAction, testLine.httpMeth, testLine.paramExt) + _, _, resultStatus := parseBodyRevAndSearch(got) + if resultStatus != 400 { + t.Errorf("Start testClient() (%v) = %v, want %v", testLine.name, resultStatus, 400) + } + } + + // Test 4: Try to get the JSON document from key 1 revision () + // The http parameter rev is set but not defined + // (Expected: The last valid revision of the key {current revision}) + { + testLine := &tests[0][0] + got := testClient(testLine.keySeqNbr, testLine.revNbr, testLine.cliAction, testLine.httpMeth, testLine.paramExt) + _, fullAnswer, resultStatus := parseBodyRevAndSearch(got) + if resultStatus != 200 && fullAnswer.RevNbr != testLine.revNbr { + t.Errorf("Start testClient() (%v) = %v, want %v", testLine.name, resultStatus, 400) + } + } + + // Test 5: Try to get the field () from the current JSON document + // The http parameter search is set but not defined + // (Expected: The last valid revision of the key {current revision}) + { + testLine := &tests[0][1] + got := testClient(testLine.keySeqNbr, testLine.revNbr, testLine.cliAction, testLine.httpMeth, testLine.paramExt) + _, fullAnswer, resultStatus := parseBodyRevAndSearch(got) + if resultStatus != 200 && fullAnswer.RevNbr != testLine.revNbr { + t.Errorf("Start testClient() (%v) = %v, want %v", testLine.name, resultStatus, 400) + } + } + + // Test 6: Try to get the field () from the revision () + // The http parameters search and rev are set but not defined + // (Expected: The last valid revision of the key {current revision}) + { + testLine := &tests[1][0] + got := testClient(testLine.keySeqNbr, testLine.revNbr, testLine.cliAction, testLine.httpMeth, testLine.paramExt) + _, fullAnswer, resultStatus := parseBodyRevAndSearch(got) + if resultStatus != 200 && fullAnswer.RevNbr != testLine.revNbr { + t.Errorf("Start testClient() (%v) = %v, want %v", testLine.name, resultStatus, 400) + } + } + + // Post job: Clean up the environment + testClient(tests[0][0].keySeqNbr, tests[0][0].revNbr, actionDel, DELETE, "") + testClient(tests[1][0].keySeqNbr, tests[1][0].revNbr, actionDel, DELETE, "") + testClient(tests[2][0].keySeqNbr, tests[2][0].revNbr, actionDel, DELETE, "") +} + +// Here valid standard parser. Accepts the response of the testClient, +// decodes it and returns the following: +// +// @var int (1) = JSON field RevNbr (int) +// @var *fullRespAnswer = In struct decoded JSOn content from kvmstoreserver +// @var int (2) = The http status code from the response header +func parseBodyRevAndSearch(resp *http.Response) (int, *fullRespAnswer, int) { + + var revNbrResult int + var fullAnswer fullRespAnswer + + body, errBody := ioutil.ReadAll(resp.Body) + if errBody != nil { + errMsg := fmt.Sprintf("Can not read body content (OrigErr)-> %v", errBody) + panic(errMsg) + } + + if resp.StatusCode == 200 { + errJSONOuter := json.Unmarshal(body, &revNbrResult) + if errJSONOuter != nil { + errJSONInner := json.Unmarshal(body, &fullAnswer) + if errJSONInner != nil { + errMsg := fmt.Sprintf("Can not decode JSON from body (OK Response; oter or inner) (OrigErr)-> %v", errJSONInner) + panic(errMsg) + } + return 0, &fullAnswer, resp.StatusCode + } + } + + return revNbrResult, &fullAnswer, resp.StatusCode +} + +type fullRespAnswer struct { + SystemName string `json:"system_name"` + SystemNumber int `json:"system_number"` + SystemVersion float64 `json:"system_version"` + SystemActive bool `json:"system_active"` + SystemNull interface{} `json:"system_null"` + RevNbr int `json:"rev_nbr"` +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_005_test.go b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_005_test.go new file mode 100755 index 0000000..62e75b5 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_005_test.go @@ -0,0 +1,121 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: testCaseRef_4_3_005_test.go + * Version: 1.0.0 + * Date: 2018-01-12 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" +) + +// Test4_3_005_test first inserts a new key into the server. Then the testClient +// creates two more revisions. The exam is passed if the JSON inside RevNbr +// field returns the number 2 via testClient +// (the check takes place in the parser) +func Test4_3_005_test(t *testing.T) { + + // Create test data + tests := []struct { + name string + keySeqNbr int + revNbr int + cliAction clientAction + httpMeth string + }{ + // Test sequence 1 + {name: "Test 1_1: Try to insert entry first time (Controller /add/ | Method POST)", keySeqNbr: 500, revNbr: 0, cliAction: actionAdd, httpMeth: POST}, + {name: "Test 1_2: Try to insert entry second time (Controller /add/ | Method POST)", keySeqNbr: 500, revNbr: 1, cliAction: actionAdd, httpMeth: POST}, + {name: "Test 1_3: Try to insert entry third time (Controller /add/ | Method POST)", keySeqNbr: 500, revNbr: 2, cliAction: actionAdd, httpMeth: POST}, + } + + var got *http.Response + + // Start a test server in a separate gourutine + runKvmssTestInstance() + + // Clean up the environment (if there are remnants of the last test) + testClient(tests[0].keySeqNbr, tests[2].revNbr, actionDel, DELETE, "") + + // Execute the test series + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got = testClient(tt.keySeqNbr, tt.revNbr, tt.cliAction, tt.httpMeth, "") + }) + } + if result, status := parseBodyRev(got); !result { + t.Errorf("Start testClient() (Try to insert 3 entries) = %v, want %v", status, 2) + } + + // Post job: Clean up the environment + testClient(tests[0].keySeqNbr, tests[2].revNbr, actionDel, DELETE, "") +} + +// Here valid standard parser. Accepts the response of the testClient, +// decodes it and returns the following: +// +// @var bool = If the JSON field NewRevisionNumber from response (NewRevisionNumber != 2) == false +// @var int = The number from the JSON field NewRevisionNumber of the current respone +func parseBodyRev(resp *http.Response) (bool, int) { + + innerStruct := struct { + StatusCode int `json:"status_code"` + Description string `json:"description"` + NewRevisionNumber int `json:"new_revision_number"` + }{} + + body, errBody := ioutil.ReadAll(resp.Body) + if errBody != nil { + errMsg := fmt.Sprintf("Can not read body content (OrigErr)-> %v", errBody) + panic(errMsg) + } + + errJSON := json.Unmarshal(body, &innerStruct) + if errJSON != nil { + errMsg := fmt.Sprintf("Can not decode JSON from body (OrigErr)-> %v", errJSON) + panic(errMsg) + } + + if innerStruct.NewRevisionNumber != 2 { + return false, innerStruct.NewRevisionNumber + } + + return true, innerStruct.NewRevisionNumber +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_006_test.go b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_006_test.go new file mode 100755 index 0000000..dffd45e --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/testCaseRef_4_3_006_test.go @@ -0,0 +1,158 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: testCaseRef_4_3_006_test.go + * Version: 1.0.0 + * Date: 2018-01-13 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" +) + +// Test4_3_006_test adds an entry to the kvmstoreserver and deletes it again. +// This process is repeated three times. At each repetition it is checked if a +// positive status code (200) comes back and if the deletion text is contained +// (All information was deleted) +func Test4_3_006_test(t *testing.T) { + + // Create test struct for the test data + type innerStruct []struct { + name string + keySeqNbr int + revNbr int + cliAction clientAction + httpMeth string + } + + // Create test data + insertValues := map[int]innerStruct{} + insertValues = make(map[int]innerStruct, 0) + insertValues[0] = innerStruct{ + // Test sequence 1 + {name: "Test 1_1: Try to insert entry first time (Controller /add/ | Method POST)", keySeqNbr: 700, revNbr: 0, cliAction: actionAdd, httpMeth: POST}, + {name: "Test 1_2: Try to delete entry (Controller /del/ | Method DELETE)", keySeqNbr: 700, revNbr: 0, cliAction: actionDel, httpMeth: DELETE}, + } + insertValues[1] = innerStruct{ + // Test sequence 2 + {name: "Test 2_1: Try to insert entry first time (Controller /add/ | Method POST)", keySeqNbr: 701, revNbr: 0, cliAction: actionAdd, httpMeth: POST}, + {name: "Test 2_2: Try to delete entry (Controller /del/ | Method DELETE)", keySeqNbr: 701, revNbr: 0, cliAction: actionDel, httpMeth: DELETE}, + } + insertValues[2] = innerStruct{ + // Test sequence 3 + {name: "Test 3_1: Try to insert entry first time (Controller /add/ | Method POST)", keySeqNbr: 702, revNbr: 0, cliAction: actionAdd, httpMeth: POST}, + {name: "Test 3_2: Try to delete entry (Controller /del/ | Method DELETE)", keySeqNbr: 702, revNbr: 0, cliAction: actionDel, httpMeth: DELETE}, + } + + // Create test data (delete instructions) + deleteValues := map[int]innerStruct{} + deleteValues = make(map[int]innerStruct, 0) + deleteValues[0] = innerStruct{ + // Delete instuctions for all keys + {name: "Test 1_3: Try to delete entry (Controller /get/ | Method GET)", keySeqNbr: 700, revNbr: 0, cliAction: actionGet, httpMeth: GET}, + {name: "Test 2_3: Try to delete entry (Controller /get/ | Method GET)", keySeqNbr: 701, revNbr: 0, cliAction: actionGet, httpMeth: GET}, + {name: "Test 3_3: Try to delete entry (Controller /get/ | Method GET)", keySeqNbr: 702, revNbr: 0, cliAction: actionGet, httpMeth: GET}, + } + + // Start a test server in a separate gourutine + runKvmssTestInstance() + + // Clean up the environment (if there are remnants of the last test) + testClient(insertValues[0][0].keySeqNbr, insertValues[0][0].revNbr, actionDel, DELETE, "") + testClient(insertValues[1][0].keySeqNbr, insertValues[1][0].revNbr, actionDel, DELETE, "") + testClient(insertValues[2][0].keySeqNbr, insertValues[2][0].revNbr, actionDel, DELETE, "") + + // Execute the test series + for _, insertOuter := range insertValues { + for _, insertInner := range insertOuter { + t.Run(insertInner.name, func(t *testing.T) { + testClient(insertInner.keySeqNbr, insertInner.revNbr, insertInner.cliAction, insertInner.httpMeth, "") + }) + } + } + + for _, outer := range deleteValues { + for _, tt := range outer { + got := testClient(tt.keySeqNbr, tt.revNbr, tt.cliAction, tt.httpMeth, "") + if result, status, errMsg := parseBodyAfterDel(got); result { + t.Errorf("Start testClient() (%v) = %v - %v, want %v - %v", tt, status, errMsg, 400, "The container with the name \"...\" existed once, but its contents were deleted") + } + } + } + + // Post job: Clean up the environment + testClient(insertValues[0][0].keySeqNbr, insertValues[0][0].revNbr, actionDel, DELETE, "") + testClient(insertValues[1][0].keySeqNbr, insertValues[1][0].revNbr, actionDel, DELETE, "") + testClient(insertValues[2][0].keySeqNbr, insertValues[2][0].revNbr, actionDel, DELETE, "") +} + +// Here valid standard parser. Accepts the response of the testClient, +// decodes it and returns the following: +// +// @var bool = If the JSON field NewRevisionNumber from response (StatusCode != 200) == false +// @var int = The status code from the current reponse +// @var string = The description JSON field of the current response +func parseBodyAfterDel(resp *http.Response) (bool, int, string) { + + innerStruct := struct { + StatusCode int `json:"status_code"` + Description string `json:"description"` + OriginalErrorMessage string `json:"original_error_message"` + }{} + + body, errBody := ioutil.ReadAll(resp.Body) + if errBody != nil { + errMsg := fmt.Sprintf("Can not read body content (OrigErr)-> %v", errBody) + panic(errMsg) + } + + errJSON := json.Unmarshal(body, &innerStruct) + if errJSON != nil { + errMsg := fmt.Sprintf("Can not decode JSON from body (OrigErr)-> %v", errJSON) + panic(errMsg) + } + + if innerStruct.StatusCode != 400 || + !strings.Contains(innerStruct.OriginalErrorMessage, "existed once, but its contents were deleted") { + return true, innerStruct.StatusCode, innerStruct.OriginalErrorMessage + } + + return false, innerStruct.StatusCode, innerStruct.OriginalErrorMessage +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver/testing_essentials.go b/kvmstoreserver_solution/src/kvmstoreserver/testing_essentials.go new file mode 100755 index 0000000..5e6bece --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver/testing_essentials.go @@ -0,0 +1,185 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: testCaseRef_4_3_006_test.go + * Version: 1.0.0 + * Date: 2018-01-12 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package main + +import ( + "bytes" + "fmt" + "net/http" + "strconv" + "time" +) + +//***************************************************************************** +//* +//* Declarations: Constants +//* +//***************************************************************************** + +// clientAction alias type for uint8 +type clientAction uint8 + +// Enum to define the client request action +const ( + actionAdd clientAction = iota + actionGet + actionDel +) + +// Enum with aliases for the HTTP methods +const ( + // GET is a alias for string "GET" + GET string = "GET" + + // POST is a alias for string "POST" + POST string = "POST" + + // DELETE is a alias for string "DELETE" + DELETE string = "DELETE" +) + +// Client and (partial Server) configuration parameters +const ( + pathToTestConfiguration string = "C:/Users/tbogd/GIT/gitlab.com/tbogdanovic/Diplomarbeit_NDS_16NI/CODE/kvmstoreserver_solution/etc/kvmstoreserver_test.conf" + + // Replace here the hostname (or IP) and the port with the parameters + // from the config file above + kvmstoreserverNameOrIP string = "192.168.117.86" + serverPortTest string = "3345" + + // Don not touch the settings below + serverStartDelay int = 2 + + addRoute string = "http://" + kvmstoreserverNameOrIP + ":" + serverPortTest + "/add/" + getRoute string = "http://" + kvmstoreserverNameOrIP + ":" + serverPortTest + "/get/" + delRoute string = "http://" + kvmstoreserverNameOrIP + ":" + serverPortTest + "/del/" +) + +//***************************************************************************** +//* +//* Private Functions +//* +//***************************************************************************** + +// runKvmssTestInstance starts a kvmstoreserver in a separate +// goroutine and waits 2 seconds until everything is ready. +// (!!! This time must be deducted during time measurements !!!) +func runKvmssTestInstance() { + + go func() { + testkvvmsrv := newAppServer(true, pathToTestConfiguration) + testkvvmsrv.start() + testkvvmsrv.wait() + }() + + time.Sleep(time.Second * time.Duration(serverStartDelay)) +} + +// This is a dynamic test clinet, which you can give a sequence number, from +// which it then generates a valid key name. In addition, you can also give him +// the RevNbr, which is written in the JSON document. To send a request, the +// action can be given, what needs to be addressed (add, get, del), as well as +// the HTTP Mtheode which should be written in the header. The last parameter +// allows the setting of free parameters, which are appended to the url call. +// The result is an HTTP response. +// (Attention, the body of the response (reader) is NOT closed!) +func testClient(keyNbr, revNbr int, action clientAction, httpMeth string, paramExt string) *http.Response { + + // Intialize a request body - default pattern + keyNbrStr := strconv.Itoa(keyNbr) + newName := "Testsystem_Name_" + keyNbrStr + newRev := revNbr + newNbr := keyNbr + newVers := float64(keyNbr) + 0.99999999 + newAct := keyNbr%2 == 0 + newNull := "null" + + buildBodyRequestADD := func() *bytes.Reader { + return bytes.NewReader([]byte( + fmt.Sprintf(`{"system_name": "%v","system_number": %v,"system_version": %v,"system_active": %v,"system_null": %v, "rev_nbr": %v}`, + newName, newNbr, newVers, newAct, newNull, newRev), + )) + } + + buildBodyRequestDEL := func() *bytes.Reader { + return bytes.NewReader([]byte( + fmt.Sprintf(`{"key_name": "%v","confirm_delete": true}`, + newName), + )) + } + + // Initialize and run a client request and catch and return a + // reference as output + client := &http.Client{Timeout: time.Second * 60} + var callURL string + var req *http.Request + var reqBuildError error + + switch action { + case actionAdd: + callURL = addRoute + newName + req, reqBuildError = http.NewRequest(httpMeth, callURL, buildBodyRequestADD()) + case actionGet: + callURL = getRoute + newName + + if paramExt != "" { + callURL = callURL + paramExt + } + req, reqBuildError = http.NewRequest(httpMeth, callURL, nil) + case actionDel: + callURL = delRoute + newName + req, reqBuildError = http.NewRequest(httpMeth, callURL, buildBodyRequestDEL()) + } + + if reqBuildError != nil { + panic("Error by building request") + } + + req.Header.Set("User-Agent", "Injection-Client-storeserver-1.0.0") + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + panic("Can not call target URL (Go internal client agent)") + } + + // The body (reader) is not closed here! + + return resp +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/essentials/successJsonRespone.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/essentials/successJsonRespone.go new file mode 100755 index 0000000..068a603 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/essentials/successJsonRespone.go @@ -0,0 +1,109 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: successJsonResponse.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package essentials + +import ( + "encoding/json" + "net/http" +) + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// SendSuccessJSONAdd Creates a JSON message with the last (current) revision +// number and using its own internal structure and writes the result directly +// into the ResponseWriter +func SendSuccessJSONAdd(writer http.ResponseWriter, statusCode, + + newRevNbr int, customText string) { + + if customText == "" { + customText = "Operation successfully finished" + } + + innerAswerStruct := &struct { + StatusCode int `json:"status_code"` + Description string `json:"description"` + NewRevisionNumber int `json:"new_revision_number"` + }{ + StatusCode: statusCode, + Description: customText, + NewRevisionNumber: newRevNbr, + } + + jsonOutput, err := json.Marshal(innerAswerStruct) + if err != nil { + panic("Internal error when sending the positive Add JSON response. Operation has been successful anyway") + } + + writer.WriteHeader(statusCode) + writer.Write(jsonOutput) +} + +// SendSuccessJSONDel Creates a JSON message with the original key Name and +// using its own internal structure and writes the result directly into +// the ResponseWriter +func SendSuccessJSONDel(writer http.ResponseWriter, statusCode int, + + keyName, customText string) { + if customText == "" { + customText = "Operation successfully finished" + } + + innerAswerStruct := &struct { + StatusCode int `json:"status_code"` + Description string `json:"description"` + KeyName string `json:"key_name"` + }{ + StatusCode: statusCode, + Description: customText, + KeyName: keyName, + } + + jsonOutput, err := json.Marshal(innerAswerStruct) + if err != nil { + panic("Internal error when sending the positive Delete JSON response. Operation has been successful anyway") + } + + writer.WriteHeader(statusCode) + writer.Write(jsonOutput) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/addFinalHandler.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/addFinalHandler.go new file mode 100755 index 0000000..ec24825 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/addFinalHandler.go @@ -0,0 +1,95 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: addFinalHandler.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package finalHandlers + +import ( + "encoding/json" + es "essentials" + answer "kvmstoreserver_utils/HttpHandlers/essentials" + bth "kvmstoreserver_utils/bTreeHandling" + eh "kvmstoreserver_utils/errorHandling" + knh "kvmstoreserver_utils/keyNameHandling" + "net/http" + "net/url" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Public Functions: Final Handler +//* +//***************************************************************************** + +// AddFinalHandler includes all the logic to add a document. +// +// The logic is equivalent to the use -Entgegennehmen- +func AddFinalHandler(w http.ResponseWriter, r *http.Request) { + + defer eh.Try("FinalHandler->AddFinalHandler()") + es.InjectJSONTypeToHeader(w) + + parsedKeyName, errKeyParser := url.PathUnescape( + es.CutKeyFromURL(r.RequestURI)) + eh.IfErrBuildJSONAndOrPanic(w, errKeyParser, http.StatusBadRequest, + "Invalid character in key name", es.DoPanic) + + keyCtx, errKeyName := knh.NewKeyContext(parsedKeyName) + eh.IfErrBuildJSONAndOrPanic(w, errKeyName, http.StatusBadRequest, + "Error by Key to=> ID mapping - Maybe forget the name?", es.DoPanic) + + newModel := bth.DataModel{} + newModel.MetaHeader = bth.NewMetaData(r) + + jsonDecoder := json.NewDecoder(r.Body) + errDecode := jsonDecoder.Decode(&newModel.Data) + eh.IfErrBuildJSONAndOrPanic(w, errDecode, http.StatusInternalServerError, + "Please check the syntax of your JSON document, there is an error", + es.DoPanic) + + currentRevNbr, errInsert := bth.NewBtree().Insert(keyCtx, &newModel) + eh.IfErrBuildJSONAndOrPanic(w, errInsert, http.StatusInternalServerError, + "When trying to write the data on the store a mistake has occurred", + es.DoPanic) + + log.Infof("Inserted data into node -> (ID: %v) | (Key name: %v) | (RevNbr: %v) -> for (Client: %v)", + keyCtx.GetNodeID(), keyCtx.GetKeyStrName(), currentRevNbr, r.RemoteAddr) + + answer.SendSuccessJSONAdd(w, http.StatusCreated, currentRevNbr, "") +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/delFinalHandler.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/delFinalHandler.go new file mode 100755 index 0000000..5d70c0b --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/delFinalHandler.go @@ -0,0 +1,134 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: delFinalHandler.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package finalHandlers + +import ( + "encoding/json" + es "essentials" + "fmt" + answer "kvmstoreserver_utils/HttpHandlers/essentials" + bth "kvmstoreserver_utils/bTreeHandling" + eh "kvmstoreserver_utils/errorHandling" + knh "kvmstoreserver_utils/keyNameHandling" + "net/http" + "net/url" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Structure: deleteConfirm +//* +//***************************************************************************** + +// deleteConfirm ... +type deleteConfirm struct { + KeyName string `json:"key_name"` + ConfirmDelete bool `json:"confirm_delete"` +} + +//******************** Methods ************************************************ + +func (slf *deleteConfirm) notEqualTo(s string) bool { return slf.KeyName != s } + +func (slf *deleteConfirm) notConfirmed() bool { return slf.ConfirmDelete != true } + +//***************************************************************************** +//* +//* Public Functions: Final Handler +//* +//***************************************************************************** + +// DelFinalHandler deletes the content of a node and its data stored at +// harddisk +// +// The logic is equivalent to the use -loeschen- +func DelFinalHandler(w http.ResponseWriter, r *http.Request) { + + defer eh.Try("FinalHandler->DelFinalHandler()") + es.InjectJSONTypeToHeader(w) + + parsedKeyName, errKeyParser := url.PathUnescape( + es.CutKeyFromURL(r.RequestURI)) + eh.IfErrBuildJSONAndOrPanic(w, errKeyParser, http.StatusBadRequest, + "Invalid character in key name", es.DoPanic) + + keyCtx, errKeyName := knh.NewKeyContext(parsedKeyName) + eh.IfErrBuildJSONAndOrPanic(w, errKeyName, http.StatusInternalServerError, + "Error by Key to=> ID mapping - Maybe forget the name?", es.DoPanic) + + newDelConfirm := deleteConfirm{} + + newJSONDecoder := json.NewDecoder(r.Body) + + errDecode := newJSONDecoder.Decode(&newDelConfirm) + eh.IfErrBuildJSONAndOrPanic(w, errDecode, http.StatusInternalServerError, + "Please check the syntax of your JSON document, there is an error", + es.DoPanic) + + if newDelConfirm.notEqualTo(keyCtx.GetKeyStrName()) { + eh.IfErrBuildJSONAndOrPanic(w, + fmt.Errorf("Your URL key and the key name in the JSON are not equal | (URL)-> %v != (JSON)-> %v", + keyCtx.GetKeyStrName(), newDelConfirm.KeyName), + http.StatusBadRequest, + "Your key name does not correspond to the name in URL", es.DoPanic) + } + if newDelConfirm.notConfirmed() { + eh.IfErrBuildJSONAndOrPanic(w, + fmt.Errorf("You forget to confirm the deletion | Recived-> (%v) || Wanted-> (true)", + newDelConfirm.ConfirmDelete), + http.StatusBadRequest, + "You forgot to confirm the deletion", es.DoPanic) + } + + errMember := bth.NewBtree().Member(keyCtx) + eh.IfErrBuildJSONAndOrPanic(w, errMember, http.StatusBadRequest, + "It seems that the key does not exist", es.DoPanic) + + delErr := bth.NewBtree().Del(keyCtx) + eh.IfErrBuildJSONAndOrPanic(w, delErr, http.StatusInternalServerError, + "Internal storage Error. Your key has not been deleted!", es.DoPanic) + + log.Infof("Successful delete node -> (ID: %v) | (Key name: %v) -> for (Client: %v)", + keyCtx.GetNodeID(), keyCtx.GetKeyStrName(), r.RemoteAddr) + + answer.SendSuccessJSONDel(w, http.StatusOK, keyCtx.GetKeyStrName(), + "All information was deleted") +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/getFinalHandler.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/getFinalHandler.go new file mode 100755 index 0000000..074c152 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/getFinalHandler.go @@ -0,0 +1,127 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: getFinalHandler.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package finalHandlers + +import ( + "encoding/json" + es "essentials" + bth "kvmstoreserver_utils/bTreeHandling" + eh "kvmstoreserver_utils/errorHandling" + knh "kvmstoreserver_utils/keyNameHandling" + "net/http" + "net/url" + "strconv" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Public Functions: Final Handler +//* +//***************************************************************************** + +// GetFinalHandler includes all the logic to get a document, a document +// by revision or a specific key back. +// +// The logic is equivalent to the use -Zurueckliefern- +func GetFinalHandler(w http.ResponseWriter, r *http.Request) { + + defer eh.Try("FinalHandler->GetFinalHandler()") + es.InjectJSONTypeToHeader(w) + + var ( + revNbrInt *int + jsonOutput interface{} + handlerRuntimeErrors error + ) + + parsedKeyName, errKeyParser := url.PathUnescape( + es.CutKeyFromURL(r.RequestURI)) + + eh.IfErrBuildJSONAndOrPanic(w, errKeyParser, http.StatusBadRequest, + "Invalid character in key name", es.DoPanic) + + keyCtx, errKeyName := knh.NewKeyContext(parsedKeyName) + + eh.IfErrBuildJSONAndOrPanic(w, errKeyName, http.StatusBadRequest, + "Error by Key to=> ID mapping - Maybe forget the name?", es.DoPanic) + + errMember := bth.NewBtree().Member(keyCtx) + eh.IfErrBuildJSONAndOrPanic(w, errMember, http.StatusBadRequest, + "It seems that the key does not exist", es.DoPanic) + + if r.URL.Query().Get("rev") != "" { + revNbr, parseIntErr := strconv. + ParseInt(r.URL.Query().Get("rev"), 10, 32) + + eh.IfErrBuildJSONAndOrPanic(w, parseIntErr, + http.StatusInternalServerError, + "The revision number must be a number", es.DoPanic) + + parsedInt := int(revNbr) + revNbrInt = &parsedInt + } + + // If revNbrInt empty, then it is nil. GetModelOrDefault() returns by a + // nil *int the last entry (current revison) + model, errModelSearch := bth.NewBtree().Get(keyCtx).GetModelOrDefault(revNbrInt) + eh.IfErrBuildJSONAndOrPanic(w, errModelSearch, http.StatusBadRequest, + "Is this revision number really correct?", es.DoPanic) + + searchOnject := r.URL.Query().Get("search") + if searchOnject != "" { + jsonOutput, handlerRuntimeErrors = model.Search(searchOnject) + eh.IfErrBuildJSONAndOrPanic(w, handlerRuntimeErrors, http.StatusBadRequest, + "It seems like the search term is wrong, please check it again", es.DoPanic) + } else { + jsonOutput = model.Data + } + + output, handlerRuntimeErrors := json.Marshal(jsonOutput) + + eh.IfErrBuildJSONAndOrPanic(w, handlerRuntimeErrors, + http.StatusInternalServerError, + "Error by converting cotent into a JSON structure", es.DoPanic) + + log.Infof("Successful reply sent -> (ID: %v) | (Key name: %v) | (RevNbr: %v) -> send back to (Client: %v)", + keyCtx.GetNodeID(), keyCtx.GetKeyStrName(), model.RevNbr, r.RemoteAddr) + + w.Write(output) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/treeFinalHandler.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/treeFinalHandler.go new file mode 100755 index 0000000..dec1155 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/finalHandlers/treeFinalHandler.go @@ -0,0 +1,59 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: treeFinalHandler.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package finalHandlers + +import ( + "kvmstoreserver_utils/bTreeHandling" + "net/http" +) + +//***************************************************************************** +//* +//* Public Functions: Final Handler +//* +//***************************************************************************** + +// TreeFinalHandler return a JSON document (JSON array) with the +// in a Slice mappt Btree structure +func TreeFinalHandler(w http.ResponseWriter, r *http.Request) { + + btree := bTreeHandling.NewBtree() + + w.Write(btree.GetBtreeStruct()) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/httpMethodCheckers.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/httpMethodCheckers.go new file mode 100755 index 0000000..bff74ce --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/httpMethodCheckers.go @@ -0,0 +1,155 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: httpMethodCheckers.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package middlewareFunctions + +import ( + "encoding/json" + "fmt" + eh "kvmstoreserver_utils/errorHandling" + "net/http" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Declarations +//* +//***************************************************************************** + +// Shortcats for HTTP methods +// Looks more beautiful in the functions than a string +const ( + post = "POST" + get = "GET" + del = "DELETE" +) + +//***************************************************************************** +//* +//* Public Functions: Middleware functionality +//* +//***************************************************************************** + +// MWareIfMethodPost checks if the client request is from HTTP method type POST +func MWareIfMethodPost(nextFunc http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // BEGIN Handler Logic -> + if result := checkMethod(w, r, post); result == eh.Nok { + return + } + + nextFunc.ServeHTTP(w, r) + // <- END Handler Logic + + }) +} + +// MWareIfMethodGet checks if the client request is from HTTP method type Get +func MWareIfMethodGet(nextFunc http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // BEGIN Handler Logic -> + if result := checkMethod(w, r, get); result == eh.Nok { + return + } + + nextFunc.ServeHTTP(w, r) + // <- END Handler Logic + + }) +} + +// MWareIfMethodDelete checks if the client request is from HTTP method type DELETE +func MWareIfMethodDelete(nextFunc http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // BEGIN Handler Logic -> + if result := checkMethod(w, r, del); result == eh.Nok { + return + } + + nextFunc.ServeHTTP(w, r) + // <- END Handler Logic + + }) +} + +//***************************************************************************** +//* +//* Private Functions +//* +//***************************************************************************** + +// checkMethod checks the method type and returns a JSON document (error) +// in case of a wrong methed call. This function has its own inner Structure +func checkMethod(iw http.ResponseWriter, ir *http.Request, + meth string) eh.Result { + + innerAswerStruct := &struct { + StatusCode int `json:"status_code,omitempty"` + Description string `json:"description,omitempty"` + Reason string `json:"reason,omitempty"` + }{ + StatusCode: http.StatusMethodNotAllowed, + Description: fmt.Sprintf("Access denied, wrong http method"), + Reason: fmt.Sprintf("This controller allows only method -> %v", meth), + } + + if ir.Method != meth { + + jsonOutput, err := json.Marshal(innerAswerStruct) + if err != nil { + panic("Can not recover panic, kill this routine without to give the client a answer") + } + + iw.WriteHeader(http.StatusMethodNotAllowed) + iw.Write(jsonOutput) + log.Warnf("Request stopped - Wrong Http method -> (%v | Received: %v | Wanted: %v)", + ir.RemoteAddr, ir.Method, meth) + + return eh.Nok + } + + return eh.Ok +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/inputOutputLogger.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/inputOutputLogger.go new file mode 100755 index 0000000..694b517 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/inputOutputLogger.go @@ -0,0 +1,73 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: inputOutputLogger.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package middlewareFunctions + +import ( + "net/http" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Public Functions: Middleware functionality +//* +//***************************************************************************** + +// MWareInOutLogger loggs every entry in the server. In case of a goroutine +// crash, its possible to see here whether a call is left unanswered +func MWareInOutLogger(nextFunc http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // BEGIN Handler Logic -> + reqPath := r.RequestURI + remoteAddr := r.RemoteAddr + + log.Infof("Processing order received for: (Controller and KEY -> %v) from -> (%v) ", + reqPath, remoteAddr) + + nextFunc.ServeHTTP(w, r) + + log.Infof("Processing completed successfully for -> (%v) and JOB -> (Controller and KEY -> %v)", + remoteAddr, reqPath) + // <- END Handler Logic + + }) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/urIintegrityCheck.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/urIintegrityCheck.go new file mode 100755 index 0000000..8677dbe --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/HttpHandlers/middlewareFunctions/urIintegrityCheck.go @@ -0,0 +1,128 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: urlIntegretyCHecker.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package middlewareFunctions + +import ( + "errors" + es "essentials" + "fmt" + eh "kvmstoreserver_utils/errorHandling" + "net/http" + "strings" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Declarations +//* +//***************************************************************************** + +var validParams = []string{"rev", "search"} + +//***************************************************************************** +//* +//* Public Functions: Middleware functionality +//* +//***************************************************************************** + +// MWareCheckKeyInURL checks if a key name exist in the the URL call +// from the client. +func MWareCheckKeyInURL(nextFunc http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // BEGIN Handler Logic -> + + keyInUrlwithoutParams := es.CutKeyFromURL(r.RequestURI) + + if keyInUrlwithoutParams == "" || + strings.Contains(keyInUrlwithoutParams, "%26") { + + result := eh.IfErrBuildJSONAndOrPanic(w, + errors.New("Missing key name as a segment of the URL"), + http.StatusBadRequest, "Error in Middleware", es.DontPanic) + + log.Warnf("Request without key name received and abort from -> (%v)", + r.RemoteAddr) + + if result != eh.Ok { + return + } + } + + nextFunc.ServeHTTP(w, r) + // <- END Handler Logic + + }) +} + +// MwareCheckParamIntegrity allows only the known parameters +// (define in validParams). All other parameter calls are not allowed +func MwareCheckParamIntegrity(nextFunc http.Handler) http.Handler { + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // BEGIN Handler Logic -> + outer: + for param := range r.URL.Query() { + for _, vaildParam := range validParams { + if param == vaildParam { + continue outer + } + } + + result := eh.IfErrBuildJSONAndOrPanic(w, + fmt.Errorf("This parameter is not allowed -> (%v)", param), + http.StatusBadRequest, "Error in Middleware", es.DontPanic) + + log.Warnf("Request aborted - unknown parameter -> (%v) was detected from -> (%v)", + param, r.RemoteAddr) + + if result != eh.Ok { + return + } + } + + nextFunc.ServeHTTP(w, r) + // <- END Handler Logic + + }) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/btree.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/btree.go new file mode 100755 index 0000000..6bda835 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/btree.go @@ -0,0 +1,217 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: btree.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package bTreeHandling contains all the components that are necessary for the +// operation of the binary tree. Some components, such as MetaData, are not +// required, but are included here. The Pakage implements the Signleton +// Pattern. If this is removed, this package can be partially used as a +// stand-alone data type +package bTreeHandling + +import ( + "encoding/json" + "fmt" + knh "kvmstoreserver_utils/keyNameHandling" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Declarations +//* +//***************************************************************************** +var ( + // This reference is always transported to the outside + // after the first creation + binTree *btree + + // Is necessary for mapping the tree into a slice + nodeMatrixSlice []*nodeMatrix +) + +//***************************************************************************** +//* +//* STRUCTURE: Btree (Public) +//* +//***************************************************************************** + +// btree includes a reference to nodeCOntainer and provides the +// only known node (root) +// +// Implement: IBtreeController +type btree struct { + root *nodeContainer +} + +//********************* Iface Methods: IBtreeController *********************** + +// Member checks if a node exists with the passed key context in the tree. +func (slf *btree) Member(nodeCtx knh.IHandelWithIds) error { + + if slf.root != nil { + return slf.root.member(nodeCtx) + } + + return fmt.Errorf("Can not find a ressource with key name -> %v", + nodeCtx.GetKeyStrName()) +} + +// InsertContainer a complete container in the Tree. +// Is it only used by the node loader -> stage0_ext1 +func (slf *btree) InsertContainer(ct IHandelWithNodes) { + + if slf.root == nil { + slf.root = (ct).(*nodeContainer) + } else { + slf.root.insertContainer(ct) + } +} + +// Insert a dataModel in the tree. the position (nodeID) is +// read from the key context. +func (slf *btree) Insert(nodeCtx knh.IHandelWithIds, data *DataModel) (int, error) { + + if slf.root == nil { + slf.root = newNode(nodeCtx) + log.Infof("Create new ROOT node with (ID: %v) for (Key name: %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + + return slf.root.insertData(data) + } + + return slf.root.insert(nodeCtx, data) +} + +// Get returns an interface to the node container. +// This can be used to access data in the node contianer +func (slf *btree) Get(nodeCtx knh.IHandelWithIds) IHandelWithNodes { + + return slf.root.get(nodeCtx) +} + +// Del empties the node container and deletes the information on the disk. +// The Contian itself remains intact during the term of the program and +// can be addressed and filled as needed +func (slf *btree) Del(nodeCtx knh.IHandelWithIds) error { + + return slf.root.del(nodeCtx) +} + +//******************** Tree representation ************************************ + +/* +In this section is the complete functionality to map the Btree into a slice. + +It calls mapTreeIntoSlice recrucively and goes down the whole tree on the left +until it meets an end. Then the call goes back one step and takes the right +branch. If this is not empty, the function tries again first on the left side +to an end, then goes back one step and so goes the recursive call until the +tree is worked from bottom left to bottom right +*/ + +type nodeMatrix struct { + NodeID int `json:"node_id,omitempty"` + IsRootNode bool `json:"is_root_node"` + BranchLeftID int `json:"branch_left_id,omitempty"` + BranchRightID int `json:"branch_right_id,omitempty"` +} + +type emptyTree struct { + Message string `json:"message,omitempty"` +} + +// GetBtreeStruct returns the structure of the tree mapped +// into a slice. The slice is also converted into a JSON document +func (slf *btree) GetBtreeStruct() []byte { + + nodeMatrixSlice = make([]*nodeMatrix, 0) + mapTreeIntoSlice(slf.root, true) + jsonOutput, _ := json.Marshal(&nodeMatrixSlice) + if len(jsonOutput) <= 2 { + empty := &emptyTree{ + Message: "The Tree is empty :(", + } + jsonEmpty, _ := json.Marshal(empty) + return jsonEmpty + } + + nodeMatrixSlice = nil + return jsonOutput +} + +func mapTreeIntoSlice(nc *nodeContainer, isRoot bool) { + + if nc == nil { + return + } + + newNodeInfo := nodeMatrix{} + newNodeInfo.IsRootNode = isRoot + if nc.BranchLeft != nil { + newNodeInfo.BranchLeftID = nc.BranchLeft.NodeID + } + if nc.BranchRight != nil { + newNodeInfo.BranchRightID = nc.BranchRight.NodeID + } + newNodeInfo.NodeID = nc.NodeID + + nodeMatrixSlice = append(nodeMatrixSlice, &newNodeInfo) + + mapTreeIntoSlice(nc.BranchLeft, false) + mapTreeIntoSlice(nc.BranchRight, false) +} + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewBtree generates a new empty tree on the first call and saves it in the +// global variable of the package. Each call causes only the reference to the +// global variable to be passed on +func NewBtree() IBtreeController { + + if binTree == nil { + binTree = &btree{} + return binTree + } + + return binTree +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/dataModel.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/dataModel.go new file mode 100755 index 0000000..6372206 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/dataModel.go @@ -0,0 +1,72 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: dataModel.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package bTreeHandling + +import ( + "fmt" +) + +//***************************************************************************** +//* +//* Structure: DataModel +//* +//***************************************************************************** + +// DataModel Contains the revision number, the metadata, and the JSON document +// stored in a mapped interface structure +type DataModel struct { + RevNbr int `json:"rev_nbr"` + MetaHeader *MetaData `json:"meta_header"` + Data map[string]interface{} `json:"data"` +} + +// Search picks up a string and views the identifier in the map +func (slf *DataModel) Search(s string) (interface{}, error) { + + // If a key exists but is NIL, this information will also be returned as Go + // NIL. Otherwise an ERROR + for mKeyName := range slf.Data { + if s == mKeyName { + return slf.Data[s], nil + } + } + + return nil, fmt.Errorf("There is no element in the values ​​map with this name -> %v", + s) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/interfaces.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/interfaces.go new file mode 100755 index 0000000..c1aebe9 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/interfaces.go @@ -0,0 +1,84 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: interfaces.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package bTreeHandling + +import knh "kvmstoreserver_utils/keyNameHandling" + +// IBtreeController includes the logic that is needed from the +// outside to use the tree +type IBtreeController interface { + + // Insert a dataModel in the tree. the position (nodeID) is + // read from the key context. + Insert(nodeCtx knh.IHandelWithIds, data *DataModel) (int, error) + + // InsertContainer a complete container in the Tree. + // Is it only used by the node loader -> stage0_ext1 + InsertContainer(ct IHandelWithNodes) + + // Member Checks if a node exists with the passed key context in the tree. + Member(nodeCtx knh.IHandelWithIds) error + + // Get returns an interface to the node container. + // This can be used to access data in the node contianer + Get(nodeCtx knh.IHandelWithIds) IHandelWithNodes + + // Del deletes a complete node Container from the tree + Del(nodeCtx knh.IHandelWithIds) error + + // GetBtreeStruct returns the structure of the tree mapped + // into a slice. The slice is also converted into a JSON document + GetBtreeStruct() []byte +} + +// IHandelWithNodes includes the logic that is needed to work +// with node containers. The caller always keeps this interface, +// never the non-exported node container structure +type IHandelWithNodes interface { + + // GetID returns the node container ID + GetID() int + + // GetOrigKeyName returns the origianl Key name + GetOrigKeyName() string + + // GetModelOrDefault provides the required revision of the + // DataModel. Default is the last and most recent + GetModelOrDefault(revNbr *int) (*DataModel, error) +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/metaData.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/metaData.go new file mode 100755 index 0000000..662fe19 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/metaData.go @@ -0,0 +1,75 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: metaData.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package bTreeHandling + +import ( + "net/http" + "time" +) + +//***************************************************************************** +//* +//* Structure: metaData +//* +//***************************************************************************** + +// MetaData Contains the meta information of a DataModel. +type MetaData struct { + // Address of the caller client + RemoteAddr string `json:"remote_addr"` + + // When was the data model created in this server? + CreatedAt time.Time `json:"created_at"` +} + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewMetaData Generates a new MetaData object and fills it with +// the necessary infomations +func NewMetaData(req *http.Request) *MetaData { + + return &MetaData{ + RemoteAddr: req.RemoteAddr, + CreatedAt: time.Now(), + } +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/nodeContainer.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/nodeContainer.go new file mode 100755 index 0000000..3c6ba34 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/bTreeHandling/nodeContainer.go @@ -0,0 +1,334 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: nodeContainer.go + * Version: 1.0.0 + * Date: 1970-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package bTreeHandling + +import ( + "bytes" + "encoding/json" + es "essentials" + "fmt" + knh "kvmstoreserver_utils/keyNameHandling" + sh "kvmstoreserver_utils/serdeHandling" + "sync" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Structure: nodeContainer +//* +//***************************************************************************** + +// nodeContainer includes all the elements necessary to store +// data and create and maintain the node in the tree +// +// Implement: IHandelWithNodes, IHandelSerialization +type nodeContainer struct { + NodeID int `json:"node_id"` + OrigKeyName string `json:"orig_key_name"` + WriteLock sync.Mutex `json:"-"` + + BranchLeft *nodeContainer `json:"-"` + BranchRight *nodeContainer `json:"-"` + + DataContainer []*DataModel `json:"data_container"` +} + +//******************** Methods ************************************************ + +// member checks if a node exists with the passed key context in the tree. +func (slf *nodeContainer) member(nodeCtx knh.IHandelWithIds) error { + + if slf.NodeID == nodeCtx.GetNodeID() { + return nil + } + + // Left Handling + if nodeCtx.GetNodeID() < slf.NodeID { + if slf.BranchLeft != nil { + return slf.BranchLeft.member(nodeCtx) + } + } else { + // Right Handling + if slf.BranchRight != nil { + return slf.BranchRight.member(nodeCtx) + } + } + + log.Infof("Tried to find a node, but it seems it is not a member -> (Node: %v) - (Origianl Key Name: %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + + return fmt.Errorf("Can not find a ressource with key name -> %v", + nodeCtx.GetKeyStrName()) +} + +// insertContainer a complete container in the Tree. +// Is it only used by the node loader -> stage0_ext1 +func (slf *nodeContainer) insertContainer(ct IHandelWithNodes) { + + // Left Handling + if ct.GetID() < slf.NodeID { + if slf.BranchLeft == nil { + slf.BranchLeft = (ct).(*nodeContainer) + return + } + slf.BranchLeft.insertContainer(ct) + } else if ct.GetID() > slf.NodeID { + // Right Handling + if slf.BranchRight == nil { + slf.BranchRight = (ct).(*nodeContainer) + return + } + slf.BranchRight.insertContainer(ct) + } +} + +// insert a dataModel in the tree. the position (nodeID) is +// read from the key context. +func (slf *nodeContainer) insert(nodeCtx knh.IHandelWithIds, + data *DataModel) (int, error) { + + if slf.NodeID == nodeCtx.GetNodeID() { + return slf.insertData(data) + } + + // Left branch handling + if nodeCtx.GetNodeID() < slf.NodeID { + if slf.BranchLeft == nil { + slf.BranchLeft = newNode(nodeCtx) + + log.Infof("Create new node with (ID: %v) for (Key name: %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + + return slf.BranchLeft.insertData(data) + } + + return slf.BranchLeft.insert(nodeCtx, data) + } + // Right branch handling + if slf.BranchRight == nil { + slf.BranchRight = newNode(nodeCtx) + + log.Infof("Create new node with (ID: %v) for (Key name: %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + + return slf.BranchRight.insertData(data) + } + + return slf.BranchRight.insert(nodeCtx, data) +} + +// get returns an interface to the node container. +// This can be used to access data in the node contianer +func (slf *nodeContainer) get(nodeCtx knh.IHandelWithIds) IHandelWithNodes { + + if slf.NodeID == nodeCtx.GetNodeID() { + log.Infof("Node found and returned -> (Node: %v) - (Origianl Key Name: %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + + return slf + } + + // Left Handling + if nodeCtx.GetNodeID() < slf.NodeID { + return slf.BranchLeft.get(nodeCtx) + } + + // Right Handling + return slf.BranchRight.get(nodeCtx) +} + +// del empties the node container and deletes the information on the disk. +// The Contian itself remains intact during the term of the program and +// can be addressed and filled as needed +func (slf *nodeContainer) del(nodeCtx knh.IHandelWithIds) error { + + if slf.NodeID == nodeCtx.GetNodeID() { + + if slf.DataContainer != nil { + deleteStorage := sh.DriverFactory(es.Delete) + if delErr := deleteStorage(slf); delErr != nil { + + log.Infof("Internal storage problem, can not delete node with -> (ID: %v) | (Key name: %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + + return fmt.Errorf("Internal storage problem, can not delete node with -> (ID: %v) | (Key name: %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + } + + slf.DataContainer = nil + + log.Infof("Deleted all datas of -> (Node: %v) - (Origianl Key Name %v)", + nodeCtx.GetNodeID(), nodeCtx.GetKeyStrName()) + + return nil + } + + log.Infof("The container with the key \"%V\" is empty, there is nothing to delete in it", + nodeCtx.GetKeyStrName()) + + return fmt.Errorf("The container with the key \"%v\" is empty, there is nothing to delete in it", + nodeCtx.GetKeyStrName()) + } + + // Left Handling + if nodeCtx.GetNodeID() < slf.NodeID { + return slf.BranchLeft.del(nodeCtx) + } + + // Right Handling + return slf.BranchRight.del(nodeCtx) + +} + +// insertData writes the data (DataModel) into the slice of the container. +// The container is locked during this operation (RW) +func (slf *nodeContainer) insertData(data *DataModel) (int, error) { + + defer slf.WriteLock.Unlock() + slf.WriteLock.Lock() + + lastRevNbr := len(slf.DataContainer) + data.RevNbr = lastRevNbr + slf.DataContainer = append(slf.DataContainer, data) + + saveStorage := sh.DriverFactory(es.Save) + + if saveErr := saveStorage(slf); saveErr != nil { + slf.DataContainer[lastRevNbr] = nil + + log.Infof("A storage medium error prevented the creation of the new revision -> (Rev: %v) -> (Current: %v)", + lastRevNbr, lastRevNbr-1) + + return 0, fmt.Errorf("A storage medium error prevented the creation of the new revision -> (Rev: %v) -> (Current: %v)", + lastRevNbr, lastRevNbr-1) + + } + + log.Infof("Inserted new content into -> (Node: %v) - (Origianl Key Name: %v) | (Current RevNbr.: %v)", + slf.NodeID, slf.OrigKeyName, lastRevNbr) + + return lastRevNbr, nil +} + +//******************** Interface: IHandelWithNodes **************************** + +// GetID returns the node container ID +func (slf *nodeContainer) GetID() int { return slf.NodeID } + +// GetOrigKeyName returns the origianl Key name +func (slf *nodeContainer) GetOrigKeyName() string { return slf.OrigKeyName } + +// GetModelOrDefault provides the required revision of the +// DataModel. Default is the last and most recent +func (slf *nodeContainer) GetModelOrDefault(revNbr *int) (*DataModel, error) { + + if slf.DataContainer != nil { + sliceLenght := len(slf.DataContainer) + if revNbr != nil { + if sliceLenght > *revNbr && *revNbr >= 0 { + return slf.DataContainer[*revNbr], nil + } + + return nil, fmt.Errorf( + "Can not find the revision number - Valid range for this key -> 0 - %v", + sliceLenght-1) + } + + return slf.DataContainer[sliceLenght-1], nil + } + + return nil, fmt.Errorf( + `The container with the name "%v" existed once, but its contents were deleted`, + slf.OrigKeyName) +} + +//******************** Interface: IHandelSerialization ************************ + +// GetNodeID redirect to GetID() and retruns the node container ID +func (slf *nodeContainer) GetNodeID() int { + return slf.NodeID +} + +// Marshal generates a JSON document form its self +func (slf *nodeContainer) Marshal() []byte { + + jsonOutput, _ := json.Marshal(slf) + + return jsonOutput +} + +//***************************************************************************** +//* +//* Private Functions +//* +//***************************************************************************** + +// newNode generates a new empty node with the ID from key context +func newNode(nodeCtx knh.IHandelWithIds) *nodeContainer { + + return &nodeContainer{ + NodeID: nodeCtx.GetNodeID(), + OrigKeyName: nodeCtx.GetKeyStrName(), + } +} + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// CreateContainerFromSource creates a complete new node container, which was +// picked up by the filessystem loader and converted into a reader +func CreateContainerFromSource(r *bytes.Reader) IHandelWithNodes { + + var newContainer nodeContainer + jsonDecoder := json.NewDecoder(r) + + decodeErr := jsonDecoder.Decode(&newContainer) + if decodeErr != nil { + errMsg := fmt.Sprintf("Apparently, manipulations have been made to a file. Abort (OrigMsg)-> %v", + decodeErr.Error()) + panic(errMsg) + } + + return &newContainer +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/catcher.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/catcher.go new file mode 100755 index 0000000..093979b --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/catcher.go @@ -0,0 +1,86 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: catcher.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package errorHandling + +import ( + "encoding/json" + es "essentials" + "net/http" +) + +// IfErrBuildJSONAndOrPanic accepts the responewriter, the origianl error, +// an HTTP congestion code and its own message. If the error !s= nil, you can +// use the control enum to define whether this function should trigger a panic +// or simply output an error per result +func IfErrBuildJSONAndOrPanic(writer http.ResponseWriter, + origErr error, statusCode int, customErrMsg string, doPanic es.Control) Result { + + if origErr != nil { + + if customErrMsg == "" { + customErrMsg = "No further description" + } + + innerAswerStruct := &struct { + StatusCode int `json:"status_code"` + Description string `json:"description"` + OriginalErrorMessage string `json:"original_error_message"` + }{ + StatusCode: statusCode, + Description: customErrMsg, + OriginalErrorMessage: origErr.Error(), + } + + jsonOutput, err := json.Marshal(innerAswerStruct) + if err != nil { + panic("Can not recover panic, kill this routine without to give the client a answer") + } + + writer.WriteHeader(statusCode) + writer.Write(jsonOutput) + + if doPanic == es.DoPanic { + panic(innerAswerStruct.OriginalErrorMessage) + } + + return Nok + } + + return Ok +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/checkErrAndForward.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/checkErrAndForward.go new file mode 100755 index 0000000..b2b7390 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/checkErrAndForward.go @@ -0,0 +1,62 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: checkErrAndForward.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package errorHandling + +import ( + "fmt" +) + +// [OBSOLETE] +// This is a future function. It is not integrated in this project + +// CheckErrAndForward picks up an error and checks if it is != nil, if so then +// you can add your own message and forward it. Allows the formation of error +// chains (Error handling CI -> Caller Informed) +func CheckErrAndForward(origErrMsg error, customMsg string) error { + + if origErrMsg != nil { + if customMsg != "" { + return fmt.Errorf("(Additional Msg -> %v) | (Orig Msg)-> %v", + customMsg, origErrMsg.Error()) + } + return origErrMsg + } + + return nil +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/result.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/result.go new file mode 100755 index 0000000..5d57cbf --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/result.go @@ -0,0 +1,52 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: result.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package errorHandling + +// Result is a type wrapper to a uint8. Is intended for situations where +// there is a static error message and no error must be generated, but only +// announced that one is present +type Result uint8 + +const ( + // Ok result + Ok Result = iota + + // Nok result + Nok +) diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/try.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/try.go new file mode 100755 index 0000000..3ecf466 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/errorHandling/try.go @@ -0,0 +1,60 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: try.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package errorHandling + +import ( + log "github.com/judwhite/logrjack" +) + +// Try can be used in a handler function via defer. In combination with +// IfErrBuildJSONAndOrPanic you can panic an error directly from the code and +// try prevents the goroutine to crash +func Try(posText string) { + + if err := recover(); err != nil { + if posText == "" { + posText = "Unknown Position!" + } + + log.Warnf("A PANIC was recovered: Position-> %v | (Orig Err Message)-> %v", + posText, err) + + return + } +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/interfaces.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/interfaces.go new file mode 100755 index 0000000..c13fe5a --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/interfaces.go @@ -0,0 +1,52 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: interfaces.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package keyNameHandling + +// IHandelWithIds works as a getter interface. This is +// necessary so that the structure keyContext does not +// have to be exported. So nobody can manipulate data +// into the structure. This interface only realizes read +// only capabilities +type IHandelWithIds interface { + // GetKeyStrName returns the value stored in the structure + GetKeyStrName() string + + // GetNodeID returns the value stored in the structure + GetNodeID() int +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/keyNameToIdConverter.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/keyNameToIdConverter.go new file mode 100755 index 0000000..de61e11 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/keyNameToIdConverter.go @@ -0,0 +1,125 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: keyNameToIdConverter.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package keyNameHandling contains all the logic needed to convert a key +// (string) to an id (int). +// +// The transformation process was developed especially for this work +package keyNameHandling + +// nolint +import ( + "crypto/md5" + "errors" + "strconv" + "strings" +) + +//***************************************************************************** +//* +//* Structure: keyContext +//* +//***************************************************************************** + +// KeyContext takes the original key and forms or calculates +// all necessary parameters. This holds it in, so you can access +// it from the outside through the interface +type keyContext struct { + keyNameAsString string + keyMd5Hash [16]byte + + // Here is the calculated node ID where the data should be stored + dataNodeID int +} + +/********************* Methods ************************************************/ + +// defDataNodeID - The functionality is described in detail in the documentation +func (slf *keyContext) defDataNodeID() { + + var uniqueIdentifierStr string + + for idx := 0; idx < 6; idx++ { + uniqueIdentifierStr += strconv.Itoa(int(slf.keyMd5Hash[idx])) + } + + uniqueIdentifier, _ := strconv.ParseInt(uniqueIdentifierStr, 10, 64) + slf.dataNodeID = int(uniqueIdentifier) +} + +// nolint +// defChkSum calc the checksum from the name (in string form) +func (slf *keyContext) defChkSum() { + slf.keyMd5Hash = md5.Sum([]byte(slf.keyNameAsString)) +} + +/********************* Interface: IHandelWithIds ******************************/ + +// GetKeyStrName returns the plain text key name from the structure +func (slf *keyContext) GetKeyStrName() string { return slf.keyNameAsString } + +// GetNodeId returns the calculated Node ID from the structure +func (slf *keyContext) GetNodeID() int { return slf.dataNodeID } + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// NewKeyContext Returns the interface IHandelWithIds, which +// contains all information on the following points: +// +// - Original Key Name as string +// - The ID of the node where to save or read data +func NewKeyContext(key string) (IHandelWithIds, error) { + + var kc keyContext + + // A backup to prevent blank input + secKey := strings.Trim(key, " ") + if len(secKey) == 0 { + return &kc, errors.New("Key name is a empty string") + } + + kc.keyNameAsString = key + kc.defChkSum() + kc.defDataNodeID() + + return &kc, nil +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/keyNameToIdConverter_test.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/keyNameToIdConverter_test.go new file mode 100755 index 0000000..3e125dd --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/keyNameHandling/keyNameToIdConverter_test.go @@ -0,0 +1,93 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: keyNameToIdConverter_test.go + * Version: 1.0.0 + * Date: 2018-01-13 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package keyNameHandling + +import ( + "reflect" + "testing" +) + +func TestNewKeyContext(t *testing.T) { + + // Crate comparative data + var iHandelWithIdsTestsystem1000 IHandelWithIds = &keyContext{ + dataNodeID: 23451191704648, + keyNameAsString: "Testsystem_Name_1000", + } + var iHandelWithIdsTheodor IHandelWithIds = &keyContext{ + dataNodeID: 8018417516249221, + keyNameAsString: "Theodor", + } + var iHandelWithIdstheodor IHandelWithIds = &keyContext{ + dataNodeID: 25422015718236214, + keyNameAsString: "theodor", + } + + // Create test data + tests := []struct { + name string + key string + want IHandelWithIds + wantErr bool + }{ + {name: "Test 1: with key name -> Testsystem_Name_1000", key: "Testsystem_Name_1000", want: iHandelWithIdsTestsystem1000, wantErr: false}, + {name: "Test 2: with key name -> Theodor", key: "Theodor", want: iHandelWithIdsTheodor, wantErr: false}, + {name: "Test 3: with key name -> theodor", key: "theodor", want: iHandelWithIdstheodor, wantErr: false}, + } + + // Execute the test series + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewKeyContext(tt.key) + + if (err != nil) != tt.wantErr { + t.Errorf("NewKeyContext() error = %v, wantErr %v", err, tt.wantErr) + return + } + + // Add the generated MD5 checksum to the comparative data + // (only the checksum) + (tt.want).(*keyContext).keyMd5Hash = (got).(*keyContext).keyMd5Hash + + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewKeyContext() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/componentFactory.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/componentFactory.go new file mode 100755 index 0000000..69c9d92 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/componentFactory.go @@ -0,0 +1,95 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: componentFactory.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package serdeHandling contains everything necessary to access a storage +// medium (currently only hard disk in this version). In later versions, the +// area SQL will be covered. This package offers two functions to decide by +// parameter which type of storage media should be used (Factory). A distinction +// is made between driver factory and loader factory. Loader facory provides +// functions that return pre-made readers. +package serdeHandling + +import ( + "bytes" + es "essentials" + "utils/configMap" +) + +// DriverFactory returns a function suitable for the storage medium. A +// distinction is made between saving and deleting. These functions are mainly +// needed at runtime +func DriverFactory(action es.Control) func(node IHandelSerialization) error { + + switch configMap.GetStringOf("serde_driver") { + + case "filesystem": + if action == es.Delete { + return deleteFromFileSystem + } + return saveToFileSystem + + case "mssql": + panic("The MSSql driver is not available in this version") + + case "postgres": + panic("The Postgres (CockroachDB) driver is not available in this version") + + default: + panic("Unknown store system driver - Please check the VAR -serde_driver- in your config file") + } +} + +// LoaderFactory returns a function suitable for the storage medium. +// These functions are mainly needed at start time (loader) +func LoaderFactory() func(nodeID int) *bytes.Reader { + + switch configMap.GetStringOf("serde_driver") { + + case "filesystem": + return loadContainerFormDisk + case "mssql": + panic("The MSSql driver is not available in this version") + + case "postgres": + panic("The Postgres (CockroachDB) driver is not available in this version") + + default: + panic("Unknown store system driver - Please check the VAR -serde_driver- in your config file") + } + +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/fileSystemDriver.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/fileSystemDriver.go new file mode 100755 index 0000000..a3759cd --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/fileSystemDriver.go @@ -0,0 +1,110 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: fileSystemDriver.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package serdeHandling + +import ( + "bytes" + "io/ioutil" + "os" + "strconv" + "utils/configMap" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Exported through factory +//* +//***************************************************************************** + +// SaveToFileSystem writes the node container to hard disk +func saveToFileSystem(node IHandelSerialization) error { + + if err := ioutil.WriteFile(defineFilePath(node.GetNodeID()), + node.Marshal(), 0660); err != nil { + return err + } + + return nil +} + +// deleteFromFileSystem deletes the file which contains the content +// of the node from the hard disk +func deleteFromFileSystem(node IHandelSerialization) error { + + if err := os.Remove(defineFilePath(node.GetNodeID())); err != nil { + return err + } + + return nil +} + +// loadContainer loads the JSON content of the complete node container +// from the hard disk as byte array and puts all into a reader. +func loadContainerFormDisk(nodeID int) *bytes.Reader { + + fullPath := defineFilePath(nodeID) + fileContent, loadErr := ioutil.ReadFile(fullPath) + if loadErr != nil { + log.Fatalf("Error by loading file from disk -> (%v)", + fullPath) + } + + newReader := bytes.NewReader(fileContent) + + return newReader +} + +//***************************************************************************** +//* +//* Private Functions +//* +//***************************************************************************** + +// defineFilePath defines the full file path of the serialized +// node container content based on the base path from the config file + +// the node ID +func defineFilePath(i int) string { + + strNodeID := strconv.Itoa(i) + fullPath := configMap.GetStringOf("storage_target") + "/" + strNodeID + ".json" + + return fullPath +} diff --git a/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/interfaces.go b/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/interfaces.go new file mode 100755 index 0000000..8967819 --- /dev/null +++ b/kvmstoreserver_solution/src/kvmstoreserver_utils/serdeHandling/interfaces.go @@ -0,0 +1,50 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: interfaces.go + * Version: 1.0.0 + * Date: 2018-01-14 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package serdeHandling + +// IHandelSerialization defines how the functions come to the node ID +// and the finished JSON document +type IHandelSerialization interface { + + // GetNodeID return the node ID + GetNodeID() int + + // Marshal retruns a byte array from the node container + Marshal() []byte +} diff --git a/kvmstoreserver_solution/src/utils/Middleware/functionChainBuilder/functionChainBuilder.go b/kvmstoreserver_solution/src/utils/Middleware/functionChainBuilder/functionChainBuilder.go new file mode 100755 index 0000000..87f9f07 --- /dev/null +++ b/kvmstoreserver_solution/src/utils/Middleware/functionChainBuilder/functionChainBuilder.go @@ -0,0 +1,143 @@ +/************************************************************************************** + * + * Project: General use + * File name: functionChainBuilder.go + * Version: 1.0.0 + * Date: 2017-08-20 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of functionChainBuilder. + * + * functionChainBuilder is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * functionChainBuilder is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with functionChainBuilder. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +/* +Package functionChainBuilder ... +*/ +package functionChainBuilder + +import ( + "net/http" +) + +//***************************************************************************** +//* +//* Declarations +//* +//***************************************************************************** + +// First-Class-Function definitions +// Here they serve as aliases to keep the signatures of methods / functions in +// the code small +type middlewareFuncAlias func(nextFunction http.Handler) http.Handler +type finalHandlerAlias func(w http.ResponseWriter, r *http.Request) + +//***************************************************************************** +//* +//* Structure ChainContainer +//* +//***************************************************************************** + +// ChainContainer includes the middleware funtions and the one +// FinalHandler. From the outside, several chains can be formed +type ChainContainer struct { + middleware []middlewareFuncAlias + finalHandler finalHandlerAlias +} + +/********************* Methods ************************************************/ + +// RegisterFunctions registered functions that correspond +// to the signature-type middlewareAlias +func (slf *ChainContainer) RegisterFunctions(mWareFuncs ...middlewareFuncAlias) *ChainContainer { + + slf.middleware = append(slf.middleware, mWareFuncs...) + + return slf +} + +// SetFinalHandler registers the final handler, which +// must contain the central logic of the controller +func (slf *ChainContainer) SetFinalHandler(fHandler finalHandlerAlias) *ChainContainer { + + slf.finalHandler = fHandler + + return slf +} + +// RunChain checks if a FinalHandler is set and starts +// the function chain of the defined series. +// If no middleware functions have been defined, the +// final handler will always be executed +func (slf *ChainContainer) RunChain() http.Handler { + + if slf.finalHandler == nil { + panic("Missing Final Handler in Function Chain!") + } + if slf.middleware != nil { + return buildMiddlewareChain(&slf.finalHandler, slf.middleware) + } + return http.HandlerFunc(slf.finalHandler) +} + +//***************************************************************************** +//* +//* Public Function +//* +//***************************************************************************** + +// NewChainConatainer creates a new empty structure from type +// ChainContainer and return it to the caller +func NewChainConatainer() *ChainContainer { + + var cContainer ChainContainer + return &cContainer +} + +//***************************************************************************** +//* +//* Private Functions +//* +//***************************************************************************** + +// buildMiddlewareChain is based on the standard pattern of go http middleware. +func buildMiddlewareChain(fHandler *finalHandlerAlias, mWareFuncs []middlewareFuncAlias) http.Handler { + + if len(mWareFuncs) == 0 { + return http.HandlerFunc(*fHandler) + } + // Unlike the original, this function uses a simple incremental process + // in the recursive call (see below). This always starts at 1 (not 0). 0 is + // the original caller for the following recursive call. 1 is the new + // function form Middleware slice. + // Go modifies the static array under the slice for every call that does not + // start from the beginning (ie 0). It cuts off the beginning to the defined + // value and forms below a new array starting from 0 (in the slice the place + // from where you started counting) + return mWareFuncs[0](buildMiddlewareChain(fHandler, mWareFuncs[1:])) +} diff --git a/kvmstoreserver_solution/src/utils/configMap/configMap.go b/kvmstoreserver_solution/src/utils/configMap/configMap.go new file mode 100755 index 0000000..cee2f51 --- /dev/null +++ b/kvmstoreserver_solution/src/utils/configMap/configMap.go @@ -0,0 +1,250 @@ +/************************************************************************************** + * + * Project: General use + * File name: configMap.go + * Version: 1.0.0 + * Date: 2017-08-19 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of configMap. + * + * configMap is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * configMap is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with configMap. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package configMap includes the logic to read in a config file and +// save it in a folder +// +// Configuration file pattern -> param name = value +package configMap + +// nolint +import ( + "crypto/md5" + "fmt" + "io/ioutil" + "strconv" + "strings" + "sync" + "utils/configPoller" + + log "github.com/judwhite/logrjack" +) + +//***************************************************************************** +//* +//* Declarations +//* +//***************************************************************************** + +// configurationFile is always transferred to the outside by +// reference. Definition takes place in this package. +// Implementation of the -Singelton Patterns- +var configurations settings + +//***************************************************************************** +//* +//* Structure: ConfigFile +//* +//***************************************************************************** + +// settings includes all necessary information from this +// package to a config file +// +// Implement: IUpdateConfig +type settings struct { + synchronous sync.Mutex + isLoaded bool + content map[string]string + fullFilePath string +} + +/********************* Methods ************************************************/ + +// loadContent loads a config file as a byte slice and +// restructures it as map[string]string +func (slf *settings) loadContent() { + + // The loading process is synchronized and all reading + // processes have to wait in case of an update + slf.synchronous.Lock() + defer slf.synchronous.Unlock() + + rawConfFileContent, err := ioutil.ReadFile(slf.fullFilePath) + if err != nil { + panic("Cannot read file") + } + + // Additional line break. Is necessary because of the parser + // below. Otherwise the last value of the config file will not be read + rawConfFileContent = append(rawConfFileContent, byte('\n')) + + // Reading the byte slice and converting to string slice (raw format). + // Separator is "=" + var newLine string + var confFileArray []string + for idx := 0; idx < len(rawConfFileContent); idx++ { + if rawConfFileContent[idx] != byte('\n') && + rawConfFileContent[idx] != byte('\r') { + newLine += string(rawConfFileContent[idx]) + } else { + if strings.Contains(newLine, "\t") { + newLine = strings.Replace(newLine, "\t", "", -1) + } + if strings.Contains(strings.TrimRight(strings. + TrimLeft(newLine, " "), " "), "=") { + if !strings.HasPrefix(newLine, "#") { + newLine = strings.Split(newLine, "#")[0] + confFileArray = append(confFileArray, newLine) + newLine = "" + } else { + newLine = "" + continue + } + } else { + newLine = "" + continue + } + } + } + + // Converting string slice to string-string map and cut all spaces + // with function trimAndConvToSting(string, int) + slf.content = make(map[string]string) + for _, line := range confFileArray { + slf.content[trimAndConvToSting(line, 0)] = trimAndConvToSting(line, 1) + } +} + +/********************* Interface: IUpdateConfig *******************************/ + +// GetMd5Sum returns the caller the CheckSum of the config file in +// in byte slice shape +// nolint +func (slf *settings) GetMd5Sum() [16]byte { + + rawConfFileContent, err := ioutil.ReadFile(slf.fullFilePath) + if err != nil { + panic("Cannot read file") + } + + return md5.Sum(rawConfFileContent) +} + +// UpdateConfig initialize the update process of this package +func (slf *settings) UpdateConfig() error { + + slf.loadContent() + + log.Infof("The configuration has been updated for the following config file -> (%v)", + slf.fullFilePath) + + return nil +} + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// Settings generates one instance of the structure ConfigFile +// and return it. Every further attempt provides a reference to the +// already created instance -Singelton Pattern- +func Settings(path string) { + + if !configurations.isLoaded { + if path == "" { + panic("Need a path to a configuration file") + } + configurations.fullFilePath = path + configurations.loadContent() + configurations.isLoaded = true + } +} + +// GetConfigMapRef ... +func GetConfigMapRef() configPoller.IUpdateConfig { return &configurations } + +// GetStringOf returns the search value as string +func GetStringOf(search string) string { return configurations.content[search] } + +// GetInt32Of tries to cast the search value into a +// int32 and return the result +func GetInt32Of(search string) int32 { + + newValue, err := strconv.ParseInt(configurations.content[search], 10, 32) + if err != nil { + panicMsg := fmt.Sprintf("Cannot convert to INT32 -> %v", configurations.content[search]) + panic(panicMsg) + } + + return (int32)(newValue) +} + +// GetFloat32Of tries to cast the search value into a +// float32 and return the result +func GetFloat32Of(search string) float32 { + + newValue, err := strconv.ParseFloat(configurations.content[search], 32) + if err != nil { + panicMsg := fmt.Sprintf("Cannot convert to FLOAT32 -> %v", configurations.content[search]) + panic(panicMsg) + } + + return (float32)(newValue) +} + +// GetBoolOf tries to cast the search value into a +// boolen and return the result +func GetBoolOf(search string) bool { + + newValue, err := strconv.ParseBool(configurations.content[search]) + if err != nil { + panicMsg := fmt.Sprintf("Cannot convert to Bool -> %v", configurations.content[search]) + panic(panicMsg) + } + + return newValue +} + +//***************************************************************************** +//* +//* Private Functions +//* +//***************************************************************************** + +// trimAndConvToSting trims the input string from the right and +// left side only +func trimAndConvToSting(name string, pos int) string { + + name = strings.Split(name, "=")[pos] + name = strings.TrimLeft(name, " ") + name = strings.TrimRight(name, " ") + + return name +} diff --git a/kvmstoreserver_solution/src/utils/configPoller/configPoller.go b/kvmstoreserver_solution/src/utils/configPoller/configPoller.go new file mode 100755 index 0000000..379dfd1 --- /dev/null +++ b/kvmstoreserver_solution/src/utils/configPoller/configPoller.go @@ -0,0 +1,123 @@ +/************************************************************************************** + * + * Project: General use + * File name: configPoller.go + * Version: 1.0.0 + * Date: 2017-08-19 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of configPoller. + * + * configPoller is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * configPoller is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with configPoller. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package configPoller takes one ore more configMap per instance +// and start a gouroutine that check in a fix interval if the config file +// has changed +package configPoller + +import ( + "time" +) + +//***************************************************************************** +//* +//* Structure: confgReaderContainer +//* +//***************************************************************************** + +// confgReaderContainer is the structure containing the +// configReader and the CheckSum of the config files +type confgReaderContainer struct { + confReader IUpdateConfig + checksum [16]byte +} + +//***************************************************************************** +//* +//* Structure: configPoller +//* +//***************************************************************************** + +// ConfigPoller contains a slice of various configReaders +// isLocked regulates that always the same instance is +// sent back after the creation (Singelton Pattern) +type configPoller struct { + readers []*confgReaderContainer + + // Interval in seconds + interval int +} + +/********************* Methods ************************************************/ + +// observeChanges is executed in a separate goroutine +// and checks after specified time whether config files were changed +func (slf *configPoller) observeChanges() { + + for { + for _, reader := range slf.readers { + newChkSum := reader.confReader.GetMd5Sum() + if reader.checksum != newChkSum { + reader.confReader.UpdateConfig() + reader.checksum = newChkSum + } + } + time.Sleep(time.Second * time.Duration(slf.interval)) + } +} + +//***************************************************************************** +//* +//* Public Functions +//* +//***************************************************************************** + +// RegisterReaders accepts one or more configReaders and stores +// them in the structure configPoller, which is then executed by +// method observeChanges() in a separate goroutine +func RegisterReaders(intVal int, readers ...IUpdateConfig) { + + if len(readers) == 0 { + panic("No list of configReaders has been defined!") + } + + var cp configPoller + + for _, reader := range readers { + crc := &confgReaderContainer{ + confReader: reader, + } + crc.checksum = crc.confReader.GetMd5Sum() + cp.readers = append(cp.readers, crc) + } + cp.interval = intVal + + // Starts the poller in a separate goroutine + go cp.observeChanges() +} diff --git a/kvmstoreserver_solution/src/utils/configPoller/interfaces.go b/kvmstoreserver_solution/src/utils/configPoller/interfaces.go new file mode 100755 index 0000000..2cf1866 --- /dev/null +++ b/kvmstoreserver_solution/src/utils/configPoller/interfaces.go @@ -0,0 +1,53 @@ +/************************************************************************************** + * + * Project: General use + * File name: interfaces.go + * Version: 1.0.0 + * Date: 2017-08-19 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of configPoller. + * + * configPoller is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * configPoller is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with configPoller. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +package configPoller + +// IUpdateConfig defines how a configReader can be called to +// output its CheckSum and how to invoke a config file update +// from the outside +type IUpdateConfig interface { + // from what the checksum was + // generated does not matter here + GetMd5Sum() [16]byte + + // What the update looks like in + // the configReader is defined by + // the reader with its own private method / function + UpdateConfig() error +} diff --git a/kvmstoreserver_solution/src/versionInfo/versionInfo.go b/kvmstoreserver_solution/src/versionInfo/versionInfo.go new file mode 100755 index 0000000..afb9b92 --- /dev/null +++ b/kvmstoreserver_solution/src/versionInfo/versionInfo.go @@ -0,0 +1,86 @@ +/************************************************************************************** + * + * Project: kvmstoreserver + * File name: versionInfo.go + * Version: 1.0.0 + * Date: 2018-01-17 + * + * Autor: Bogdanovic Theodor + * Contact: t.bogdanovic@hotmail.com + * + * License: GPLv3 + * + **************************************************************************************/ +/************************************************************************************** + * Copyright 2018 Bogdanovic Theodor + * + * This file is part of kvmstoreserver. + * + * kvmstoreserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * kvmstoreserver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kvmstoreserver. If not, see . + **************************************************************************************/ +/************************************************************************************** + * Further explanations: This source code is under the license specified by the + * Autor above. Core components or other packages are still + * in source code form, under the license specified by the + * respective author. + **************************************************************************************/ + +// Package versionInfo contains constants and functions which +// provide general program information +package versionInfo + +import ( + "encoding/json" + "essentials" + "net/http" +) + +// Staticlly hard coded base information about the kvmstoreserver +const ( + programName string = "kvmstoreserver" + version string = "1.0.0" + buildTime string = "2018-02-17__18:34.000" + license string = "GPLv3" + autor string = "Bogdanovic Theodor" + contact string = "t.bogdanovic@hotmail.com" + infos string = "HBU HF NDS, Diploma Project" +) + +// VerInfoFinalHandler return a JSON document which contains essentail +// inforamtions about this program +func VerInfoFinalHandler(w http.ResponseWriter, r *http.Request) { + essentials.InjectJSONTypeToHeader(w) + + innerAswerStruct := &struct { + ProgramName string `json:"program_name,omitempty"` + Version string `json:"version,omitempty"` + BuildTime string `json:"build_time,omitempty"` + License string `json:"license,omitempty"` + Autor string `json:"autor,omitempty"` + Contact string `json:"contact,omitempty"` + Infos string `json:"infos,omitempty"` + }{ + ProgramName: programName, + Version: version, + BuildTime: buildTime, + License: license, + Autor: autor, + Contact: contact, + Infos: infos, + } + + jsonOutput, _ := json.MarshalIndent(innerAswerStruct, "", "\t") + + w.Write(jsonOutput) +} diff --git a/user-manual-de.pdf b/user-manual-de.pdf new file mode 100755 index 0000000..a25a816 Binary files /dev/null and b/user-manual-de.pdf differ