Skip to content
Snippets Groups Projects
Commit 5bb90249 authored by Malte Bauch's avatar Malte Bauch
Browse files

Merge branch 'develop' into 13-neo4j-2

parents 10929794 7f97a0a7
Branches
No related tags found
2 merge requests!43Resolve "neo4j",!18Develop
Pipeline #52599 passed with warnings
...@@ -12,35 +12,34 @@ before_script: ...@@ -12,35 +12,34 @@ before_script:
code-quality-master: code-quality-master:
image: golangci/golangci-lint:latest-alpine image: golangci/golangci-lint:latest-alpine
stage: test stage: test
only: rules:
- merge_requests - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
except: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
variables: when: manual
- $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "master"
script: script:
- git config --global url."https://$GO_MODULES_USER:$GO_MODULES_ACCESS_TOKEN@code.fbi.h-da.de".insteadOf "https://code.fbi.h-da.de"
# writes golangci-lint output to gl-code-quality-report.json # writes golangci-lint output to gl-code-quality-report.json
- golangci-lint run --config .ci/.golangci-master.yml | tee gl-code-quality-report.json - golangci-lint run --config .ci/.golangci-master.yml --out-format code-climate | tee gl-code-quality-report.json
artifacts: artifacts:
reports: reports:
codequality: gl-code-quality-report.json codequality: gl-code-quality-report.json
paths:
- gl-code-quality-report.json
code-quality: code-quality:
image: golangci/golangci-lint:latest-alpine image: golangci/golangci-lint:latest-alpine
stage: test stage: test
allow_failure: true allow_failure: true
only: rules:
- merge_requests - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != $CI_DEFAULT_BRANCH
except:
variables:
- $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"
script: script:
# writes golangci-lint output to gl-code-quality-report.json # writes golangci-lint output to gl-code-quality-report.json
- golangci-lint run --config .ci/.golangci.yml | tee gl-code-quality-report.json - golangci-lint run --config .ci/.golangci.yml--out-format code-climate | tee gl-code-quality-report.json
artifacts: artifacts:
reports: reports:
codequality: gl-code-quality-report.json codequality: gl-code-quality-report.json
paths:
- gl-code-quality-report.json
Documentation: Documentation:
before_script: before_script:
...@@ -50,9 +49,9 @@ Documentation: ...@@ -50,9 +49,9 @@ Documentation:
entrypoint: entrypoint:
- '' - ''
stage: build stage: build
only: rules:
changes: - changes:
- documentation/design/*.md - documentation/design/*.md
script: script:
- cd documentation/design - cd documentation/design
- pandoc --filter pandoc-citeproc --bibliography=bibliography.bib --csl=acm-sig-proceedings.csl - pandoc --filter pandoc-citeproc --bibliography=bibliography.bib --csl=acm-sig-proceedings.csl
...@@ -78,4 +77,3 @@ include: ...@@ -78,4 +77,3 @@ include:
- template: Security/SAST.gitlab-ci.yml - template: Security/SAST.gitlab-ci.yml
- template: Dependency-Scanning.gitlab-ci.yml - template: Dependency-Scanning.gitlab-ci.yml
- template: Security/License-Scanning.gitlab-ci.yml - template: Security/License-Scanning.gitlab-ci.yml
[[client]]
identifier = "ciena-mcp"
endpoint = "141.100.70.170:8080"
\ No newline at end of file
...@@ -3,7 +3,12 @@ package log ...@@ -3,7 +3,12 @@ package log
import ( import (
"fmt" "fmt"
"io" "io"
"log/syslog"
"os" "os"
"reflect"
"runtime"
"strconv"
"strings"
"sync" "sync"
"time" "time"
) )
...@@ -14,22 +19,47 @@ var once sync.Once ...@@ -14,22 +19,47 @@ var once sync.Once
// Logger is a wrapper for log.Logger and provides // Logger is a wrapper for log.Logger and provides
// methods to enable and disable logging. // methods to enable and disable logging.
type Logger struct { type Logger struct {
Out io.Writer DefaultWriter io.Writer
Loglevel Level LoglevelWriter map[Level]io.Writer
lock sync.Mutex toSyslog map[Level]bool
Loglevel Level
lock sync.Mutex
builder strings.Builder
}
func (l *Logger) buildMessage(level Level, syslog bool, args ...interface{}) {
if !syslog {
l.builder.WriteString(time.Now().Format(time.RFC3339))
}
l.builder.WriteRune('\t')
l.builder.WriteString(prefix(level))
l.builder.WriteRune('\t')
function, line := callers()
functionSplitted := strings.SplitAfter(function, "/")
function = functionSplitted[len(functionSplitted)-1]
l.builder.WriteString(function)
l.builder.WriteRune(':')
l.builder.WriteString(strconv.Itoa(line))
l.builder.WriteRune('\t')
l.builder.WriteString(fmt.Sprint(args...))
l.builder.WriteRune('\n')
} }
func get() *Logger { func get() *Logger {
once.Do(func() { once.Do(func() {
logger = &Logger{ logger = &Logger{
Out: os.Stdout, DefaultWriter: os.Stderr,
Loglevel: INFO, LoglevelWriter: make(map[Level]io.Writer),
lock: sync.Mutex{}, toSyslog: make(map[Level]bool),
Loglevel: INFO,
lock: sync.Mutex{},
} }
}) })
return logger return logger
} }
//Loglevel sets the verbosity of the logger
//Defaults to INFO
func Loglevel(level Level) { func Loglevel(level Level) {
l := get() l := get()
l.lock.Lock() l.lock.Lock()
...@@ -37,48 +67,101 @@ func Loglevel(level Level) { ...@@ -37,48 +67,101 @@ func Loglevel(level Level) {
l.Loglevel = level l.Loglevel = level
} }
//Output defines the output of the logger
//Defaults to os.Stderr
func Output(out io.Writer) { func Output(out io.Writer) {
l := get() l := get()
l.lock.Lock() l.lock.Lock()
defer l.lock.Unlock() defer l.lock.Unlock()
l.Out = out l.DefaultWriter = out
}
//LoglevelOutput defines a special output
//for a certain log level
func LoglevelOutput(level Level, out io.Writer) {
l := get()
l.lock.Lock()
defer l.lock.Unlock()
l.LoglevelWriter[level] = out
if reflect.TypeOf(out) == reflect.TypeOf(&syslog.Writer{}) {
l.toSyslog[level] = true
}
} }
//Debug passes the DEBUG flag and a
//message to the logger
func Debug(args ...interface{}) { func Debug(args ...interface{}) {
log(DEBUG, args...) log(DEBUG, args...)
} }
//Debug passes the DEBUG flag and a
//message to the logger
func Info(args ...interface{}) { func Info(args ...interface{}) {
log(INFO, args...) log(INFO, args...)
} }
//Warn passes the WARNING flag and a
//message to the logger
func Warn(args ...interface{}) { func Warn(args ...interface{}) {
log(WARNING, args...) log(WARNING, args...)
} }
//Error passes the ERROR flag and a
//message to the logger
func Error(args ...interface{}) { func Error(args ...interface{}) {
log(ERROR, args...) log(ERROR, args...)
} }
//Fatal passes the FATAL flag and a
//message to the logger and calls
//os.Exit(1)
func Fatal(args ...interface{}) { func Fatal(args ...interface{}) {
log(FATAL, args...) log(FATAL, args...)
os.Exit(1)
} }
//Panic passes the PANIC flag and a
//message to the logger
//Also calls builtin.panic()
func Panic(args ...interface{}) { func Panic(args ...interface{}) {
log(PANIC, args...) log(PANIC, args...)
panic(args)
} }
func log(level Level, args ...interface{}) { func log(level Level, args ...interface{}) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
l := get() l := get()
l.lock.Lock() l.lock.Lock()
defer l.lock.Unlock() defer l.lock.Unlock()
defer l.builder.Reset()
if level <= l.Loglevel { if level <= l.Loglevel {
msg := fmt.Sprint(args...) l.buildMessage(level, l.toSyslog[level], args...)
logMessage := time.Now().Format(time.RFC3339) + "\t" + prefix(level) + "\t" + msg + "\n" msg := []byte(l.builder.String())
l.Out.Write([]byte(logMessage)) writer, ok := l.LoglevelWriter[level]
var err error
if !ok {
_, err = l.DefaultWriter.Write(msg)
} else {
_, err = writer.Write(msg)
}
if err != nil {
panic(err)
}
} }
} }
func callers() (string, int) {
pc := make([]uintptr, 15)
n := runtime.Callers(5, pc)
frames := runtime.CallersFrames(pc[:n])
frame, _ := frames.Next()
return frame.Function, frame.Line
}
func prefix(level Level) string { func prefix(level Level) string {
switch level { switch level {
case PANIC: case PANIC:
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"code.fbi.h-da.de/cocsn/gosdn/log" "code.fbi.h-da.de/cocsn/gosdn/log"
"code.fbi.h-da.de/cocsn/gosdn/nucleus" "code.fbi.h-da.de/cocsn/gosdn/nucleus"
"flag" "flag"
"log/syslog"
) )
func main() { func main() {
...@@ -17,6 +18,16 @@ func main() { ...@@ -17,6 +18,16 @@ func main() {
cliSocket := *cliListenAddr + ":" + *cliListenPort cliSocket := *cliListenAddr + ":" + *cliListenPort
log.Loglevel(log.DEBUG) log.Loglevel(log.DEBUG)
syslogWriter, err := syslog.New(syslog.LOG_ALERT, "gosdn")
defer func() {
if err := syslogWriter.Close(); err != nil {
log.Fatal(err)
}
}()
if err != nil {
log.Fatal(err)
}
log.LoglevelOutput(log.INFO, syslogWriter)
// Setup a channel to communicate if goSDN should shutdown. // Setup a channel to communicate if goSDN should shutdown.
IsRunningChannel := make(chan bool) IsRunningChannel := make(chan bool)
......
...@@ -18,6 +18,10 @@ type controllerConfig struct { ...@@ -18,6 +18,10 @@ type controllerConfig struct {
ConfigPath string ConfigPath string
} }
type clientConfigs struct {
Client []interfaces.ClientConfig `toml:"client"`
}
type Core struct { type Core struct {
//Assert type with clients[key].(*MCPClient) //Assert type with clients[key].(*MCPClient)
clients map[string]interfaces.Client clients map[string]interfaces.Client
...@@ -26,33 +30,22 @@ type Core struct { ...@@ -26,33 +30,22 @@ type Core struct {
IsRunning chan bool IsRunning chan bool
} }
func (c *Core) Init(socket, configfile string, IsRunningChannel chan bool) { func (c *Core) Init(socket, configFileController, configFileClient string, IsRunningChannel chan bool) {
if configfile == "" { if err := c.readControllerConfig(configFileController); err != nil {
configfile = "gosdn.toml"
}
_, err := os.Stat(configfile)
if err != nil {
log.Fatal("Config file is missing: ", configfile)
}
c.config = controllerConfig{}
if _, err := toml.DecodeFile(configfile, &c.config); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if socket != "localhost:55055" { if socket != "localhost:55055" {
c.config.CliSocket = socket c.config.CliSocket = socket
} }
if c.config.ConfigPath == "" {
c.config.ConfigPath = configfile
}
c.AttachDatabase() c.AttachDatabase()
c.IsRunning = IsRunningChannel c.IsRunning = IsRunningChannel
//TODO: Create client config/CLI adapter if err := c.readClientConfig(configFileClient); err != nil {
c.clients["ciena-mcp"] = ciena.NewMCPClient("141.100.70.170:8080", "", "", &c.database) log.Fatal(err)
}
} }
func (c *Core) AttachDatabase() { func (c *Core) AttachDatabase() {
...@@ -61,13 +54,8 @@ func (c *Core) AttachDatabase() { ...@@ -61,13 +54,8 @@ func (c *Core) AttachDatabase() {
func (c *Core) Shutdown() { func (c *Core) Shutdown() {
stopIt := <- c.IsRunning <- c.IsRunning
if !stopIt { log.Info("Received shutdown signal. Shutting down")
log.Debug("Shutdown() received action to shutdown")
}else {
log.Debug("Shutdown() received something else.")
}
f, err := os.Create(c.config.ConfigPath) f, err := os.Create(c.config.ConfigPath)
if err != nil { if err != nil {
...@@ -77,6 +65,42 @@ func (c *Core) Shutdown() { ...@@ -77,6 +65,42 @@ func (c *Core) Shutdown() {
if err := enc.Encode(c.config); err != nil { if err := enc.Encode(c.config); err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Info("Shutdown complete")
os.Exit(0) os.Exit(0)
} }
func (c *Core)readControllerConfig(configFileController string) error {
if configFileController == "" {
configFileController = "gosdn.toml"
}
if _, err := os.Stat(configFileController); err != nil {
return err
}
c.config = controllerConfig{}
if _, err := toml.DecodeFile(configFileController, &c.config); err != nil {
return err
}
if c.config.ConfigPath == "" {
c.config.ConfigPath = configFileController
}
return nil
}
func (c *Core)readClientConfig(configFileClient string) error {
if configFileClient == "" {
configFileClient = "clients.toml"
}
if _,err := os.Stat(configFileClient); err != nil {
return err
}
clients := clientConfigs{}
if _,err := toml.DecodeFile(configFileClient, &clients); err != nil {
return err
}
for _,client := range clients.Client {
c.clients[client.Identifier] = ciena.NewMCPClient(client.Endpoint, client.Username, client.Password, &c.database, &client)
}
return nil
}
\ No newline at end of file
package interfaces package interfaces
type Client interface { type Client interface {
GetConfig() string GetConfig() ClientConfig
} }
package interfaces
type ClientConfig struct {
Identifier string `toml:"identifier"`
Endpoint string `toml:"endpoint"`
Username string `toml:"username"`
Password string `toml:"password"`
}
...@@ -7,10 +7,7 @@ import ( ...@@ -7,10 +7,7 @@ import (
"time" "time"
) )
/* //StartAndRun is used to start the core of the controller and any auxiliary services.
* This function is used to start the core of the controller and any auxiliary services.
*/
func StartAndRun(socket, filename string, IsRunningChannel chan bool) { func StartAndRun(socket, filename string, IsRunningChannel chan bool) {
log.Info("This is the network superintendent...") log.Info("This is the network superintendent...")
log.Info("Starting my ducks") log.Info("Starting my ducks")
...@@ -20,7 +17,7 @@ func StartAndRun(socket, filename string, IsRunningChannel chan bool) { ...@@ -20,7 +17,7 @@ func StartAndRun(socket, filename string, IsRunningChannel chan bool) {
clients: make(map[string]interfaces.Client), clients: make(map[string]interfaces.Client),
database: database.Database{}, database: database.Database{},
} }
core.Init(socket, filename, IsRunningChannel) core.Init(socket, filename,"", IsRunningChannel)
// Start the GRCP CLI // Start the GRCP CLI
go getCLIGoing(&core) go getCLIGoing(&core)
go core.Shutdown() go core.Shutdown()
...@@ -28,10 +25,8 @@ func StartAndRun(socket, filename string, IsRunningChannel chan bool) { ...@@ -28,10 +25,8 @@ func StartAndRun(socket, filename string, IsRunningChannel chan bool) {
log.Info("and ready for take off") log.Info("and ready for take off")
//Just to produce some signs of vitality... //Just to produce some signs of vitality...
for (true) { for {
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
log.Debug("Still alive...") log.Debug("Still alive...")
} }
log.Info("Good bye....!")
} }
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"code.fbi.h-da.de/cocsn/gosdn/database" "code.fbi.h-da.de/cocsn/gosdn/database"
"code.fbi.h-da.de/cocsn/gosdn/log" "code.fbi.h-da.de/cocsn/gosdn/log"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/interfaces"
"code.fbi.h-da.de/cocsn/gosdn/restconf/util" "code.fbi.h-da.de/cocsn/gosdn/restconf/util"
apiclient "code.fbi.h-da.de/cocsn/swagger/apis/mcp/client" apiclient "code.fbi.h-da.de/cocsn/swagger/apis/mcp/client"
"crypto/tls" "crypto/tls"
...@@ -19,15 +20,15 @@ type MCPClient struct { ...@@ -19,15 +20,15 @@ type MCPClient struct {
client *apiclient.ServiceTopologyTAPI client *apiclient.ServiceTopologyTAPI
database *database.Database database *database.Database
buffer *bytes.Buffer buffer *bytes.Buffer
config *interfaces.ClientConfig
} }
func (c MCPClient) GetConfig() string { func (c MCPClient) GetConfig() interfaces.ClientConfig {
//TODO: Fill with life return *c.config
return "..."
} }
//NewMCPClient creates a client //NewMCPClient creates a client
func NewMCPClient(endpoint, username, password string, database *database.Database) *MCPClient { func NewMCPClient(endpoint, username, password string, database *database.Database, config *interfaces.ClientConfig) *MCPClient {
// create the transport // create the transport
transport := httptransport.New(endpoint, "/", nil) transport := httptransport.New(endpoint, "/", nil)
transport.Transport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} transport.Transport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
...@@ -45,6 +46,7 @@ func NewMCPClient(endpoint, username, password string, database *database.Databa ...@@ -45,6 +46,7 @@ func NewMCPClient(endpoint, username, password string, database *database.Databa
client: client, client: client,
database: database, database: database,
buffer: buffer, buffer: buffer,
config: config,
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment