diff --git a/.dockerignore b/.dockerignore index fee485d0b465a720847a86aa6c382e785ce23833..8fff60fd57f7fba983e1473465cccbbf124caa8c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,5 +9,4 @@ test .gitlab-ci.yaml ARCHITECTURE.md CONTRIBUTING.md -Dockerfile.alpine README.md diff --git a/.gitignore b/.gitignore index 2dcac5e10f703e04f4b9194574241f179273f837..b53fc7aa87a5fada9d21e22612e99b94fdd7178c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ debug.test # Binary gosdn + +# Storage +stores/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 55009afffc562d6f22c9713c419ad5c64cbd7d53..022e37b10d723ef5de62a334eae0aa9992dc71b3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,9 +5,9 @@ variables: GOLANG_VERSION: "1.16" stages: - - .pre - build - test + - analyze - apply - integration-test - deploy diff --git a/.gitlab/ci/.build-container.yml b/.gitlab/ci/.build-container.yml index 9d01ba6399a28cbc18f29928b6ac1408448cab3d..80fa497ed33299d437a6b41cb8b8680f4497e8ab 100644 --- a/.gitlab/ci/.build-container.yml +++ b/.gitlab/ci/.build-container.yml @@ -5,6 +5,14 @@ entrypoint: [ "" ] variables: TAG: $CI_COMMIT_BRANCH + before_script: + # replace all slashes in the tag with hyphen, because slashes are not allowed in tags + - TAG=${TAG//\//-} + - mkdir -p /kaniko/.docker + - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"},\"$CI_DEPENDENCY_PROXY_SERVER\":{\"username\":\"$CI_DEPENDENCY_PROXY_USER\",\"password\":\"$CI_DEPENDENCY_PROXY_TOKEN\"}}}" > /kaniko/.docker/config.json + needs: [] + +build-testing-image: rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH variables: @@ -30,11 +38,23 @@ build-testing-image: --dockerfile "Dockerfile" --build-arg "GOLANG_VERSION=$GOLANG_VERSION" --build-arg "BUILDARGS=$BUILDARGS" + --build-arg "GITLAB_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/" --destination "$GOSDN_TESTING_IMAGE" --target "installer" <<: *build build-image: + rules: + - if: '$CI_PIPELINE_SOURCE != "merge_request_event"' + when: never + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + variables: + TAG: latest + - if: $CI_COMMIT_BRANCH == "develop" + variables: + TAG: develop + BUILDARGS: -race + - when: always script: - /kaniko/executor --cache=true @@ -42,6 +62,9 @@ build-image: --dockerfile "Dockerfile" --build-arg "GOLANG_VERSION=$GOLANG_VERSION" --build-arg "BUILDARGS=$BUILDARGS" + --build-arg "GITLAB_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/" --destination "$GOSDN_IMAGE" --destination "$CI_REGISTRY_IMAGE:$TAG" <<: *build + + #--build-arg "GITLAB_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/" diff --git a/.gitlab/ci/.code-quality-ci.yml b/.gitlab/ci/.code-quality-ci.yml index 63b53d78afe507bcd84e9dd68b95ff0ba5e8902d..bc283cf53753be249af8cb856bb0c0c75ca9a182 100644 --- a/.gitlab/ci/.code-quality-ci.yml +++ b/.gitlab/ci/.code-quality-ci.yml @@ -1,6 +1,6 @@ code-quality: - image: golangci/golangci-lint:latest-alpine - stage: test + image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/golangci/golangci-lint:latest-alpine + stage: analyze script: # writes golangci-lint output to gl-code-quality-report.json - golangci-lint run --config .gitlab/ci/.golangci-config/.golangci.yml --out-format code-climate | tee gl-code-quality-report.json diff --git a/.gitlab/ci/.containerlab-ci.yml b/.gitlab/ci/.containerlab-ci.yml index 833b7f146f2f017c7be41c866244a453a878d9fa..3fde1f9e80ce86d669faedf3c4b790bd8c13d644 100644 --- a/.gitlab/ci/.containerlab-ci.yml +++ b/.gitlab/ci/.containerlab-ci.yml @@ -5,6 +5,10 @@ variables: # Templates for Job Types .containerlab_deploy: &containerlab_deploy stage: apply + rules: + - if: '$CI_PIPELINE_SOURCE != "merge_request_event"' + when: never + - when: on_success tags: - shell before_script: @@ -16,8 +20,12 @@ variables: - docker pull ${CEOS_IMAGE} .containerlab_template: &containerlab_template - image: alpine:latest + image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine:latest stage: build + rules: + - if: '$CI_PIPELINE_SOURCE != "merge_request_event"' + when: never + - when: on_success before_script: - export PATH="${PATH}:${CI_PROJECT_DIR}/.gitlab/ci/scripts" - firstOctet=$(generate_octet.sh $CI_COMMIT_SHA) @@ -42,7 +50,7 @@ variables: containerlab:template:integration: extends: .containerlab_template variables: - CLAB_TEMPLATE: "${CI_PROJECT_DIR}/test/containerlab/complex-1.0.clab.tmpl.yml" + CLAB_TEMPLATE: "${CI_PROJECT_DIR}/test/containerlab/int01.clab.tmpl.yml" containerlab:deploy:integration: @@ -54,12 +62,7 @@ containerlab:deploy:integration: echo -e "\ GOSDN_HTTP_PORT=$(docker_host_port 8080 clab-${CLAB_NAME}-gosdn)\n\ GOSDN_GRPC_PORT=$(docker_host_port 55055 clab-${CLAB_NAME}-gosdn)\n\ - CEOS1_1_PORT=$(docker_host_port 6030 clab-${CLAB_NAME}-ceos1-1)\n\ - CEOS1_2_PORT=$(docker_host_port 6030 clab-${CLAB_NAME}-ceos1-2)\n\ - CEOS2_1_1_PORT=$(docker_host_port 6030 clab-${CLAB_NAME}-ceos2-1-1)\n\ - CEOS2_1_2_PORT=$(docker_host_port 6030 clab-${CLAB_NAME}-ceos2-1-2)\n\ - CEOS2_2_1_PORT=$(docker_host_port 6030 clab-${CLAB_NAME}-ceos2-2-1)\n\ - CEOS2_2_2_PORT=$(docker_host_port 6030 clab-${CLAB_NAME}-ceos2-2-2)" \ + CEOS1_PORT=$(docker_host_port 6030 clab-${CLAB_NAME}-ceos1)" \ > ${CI_PROJECT_DIR}/build.env - cat ${CI_PROJECT_DIR}/build.env artifacts: @@ -71,6 +74,10 @@ containerlab:deploy:integration: containerlab:destroy: + rules: + - if: '$CI_PIPELINE_SOURCE != "merge_request_event"' + when: never + - when: always stage: .post tags: - shell diff --git a/.gitlab/ci/.deploy-k8s.yml b/.gitlab/ci/.deploy-k8s.yml index bac4bcbbe1e466d32866bdef4690632cdf451121..e2d8e52baae3834784bfd8cbe1a36f38d699b3bd 100644 --- a/.gitlab/ci/.deploy-k8s.yml +++ b/.gitlab/ci/.deploy-k8s.yml @@ -1,6 +1,6 @@ build:k8s-bot: stage: build - image: golang:$GOLANG_VERSION + image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/golang:$GOLANG_VERSION rules: - if: $CI_COMMIT_BRANCH == "develop" - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH @@ -14,7 +14,7 @@ build:k8s-bot: .deploy: &deploy image: - name: bitnami/kubectl:latest + name: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/bitnami/kubectl:latest entrypoint: [""] before_script: - echo "override global before script" diff --git a/.gitlab/ci/.integration-test.yml b/.gitlab/ci/.integration-test.yml index 771560483a9c1e6fadb181dcae9812f97920eadb..cf304933eefed8cc616381afd6ffff9670791c2e 100644 --- a/.gitlab/ci/.integration-test.yml +++ b/.gitlab/ci/.integration-test.yml @@ -1,12 +1,18 @@ .integration-test: &integration-test image: $GOSDN_TESTING_IMAGE stage: integration-test + rules: + - if: '$CI_PIPELINE_SOURCE != "merge_request_event"' + when: never + - when: on_success needs: - job: "containerlab:deploy:integration" + tags: + - integration-test-docker variables: GOSDN_LOG: "nolog" GOSDN_TEST_API_ENDPOINT: "141.100.70.178:${GOSDN_GRPC_PORT}" - CEOS_TEST_ENDPOINT: "141.100.70.178:${CEOS1_1_PORT}" + CEOS_TEST_ENDPOINT: "141.100.70.178:${CEOS1_PORT}" GOSDN_TEST_USER: "admin" GOSDN_TEST_PASSWORD: "admin" @@ -15,7 +21,6 @@ integration-test:nucleus: <<: *integration-test script: - ${CI_PROJECT_DIR}/.gitlab/ci/scripts/wait-for-it.sh ${CEOS_TEST_ENDPOINT} -s -t 180 -- echo "CEOS is up" - - sleep 30 - cd ./test/integration - go test -race -v -run TestGnmi_SetIntegration - go test -race -v -run TestGnmi_GetIntegration diff --git a/.gitlab/ci/.security-and-compliance-ci.yml b/.gitlab/ci/.security-and-compliance-ci.yml index 8421e57c892737a12ccf27ef3baf763059587643..6157fbe9f352bec93876192923e95aae7482ea75 100644 --- a/.gitlab/ci/.security-and-compliance-ci.yml +++ b/.gitlab/ci/.security-and-compliance-ci.yml @@ -1,3 +1,11 @@ +.rules: &rules + stage: analyze + rules: + - if: '$CI_PIPELINE_SOURCE != "merge_request_event"' + when: never + - when: always + needs: [] + sast: variables: SAST_ANALYZER_IMAGE_TAG: '2' @@ -8,6 +16,8 @@ include: - template: Security/SAST.gitlab-ci.yml - template: Dependency-Scanning.gitlab-ci.yml - template: Security/License-Scanning.gitlab-ci.yml + # - template: Security/Secret-Detection.gitlab-ci.yml + - template: Security/Container-Scanning.gitlab-ci.yml license_scanning: rules: @@ -24,3 +34,16 @@ gosec-sast: semgrep-sast: rules: - !reference [.nightly_pipeline, rules] + +container_scanning: + stage: analyze + rules: + - if: '$CI_PIPELINE_SOURCE != "merge_request_event"' + when: never + - when: always + variables: + DOCKER_IMAGE: "${GOSDN_IMAGE}" + DOCKER_USER: "${CI_REGISTRY_USER}" + DOCKER_PASSWORD: "${CI_REGISTRY_PASSWORD}" + needs: + - build-image diff --git a/.gitlab/ci/.test.yml b/.gitlab/ci/.test.yml index 655cb1990b58351a85aef02cbfe234a37c181609..738560c401bd92eff06e30036b2fee3a0ad2c693 100644 --- a/.gitlab/ci/.test.yml +++ b/.gitlab/ci/.test.yml @@ -1,6 +1,8 @@ .test: &test image: $GOSDN_TESTING_IMAGE stage: test + rules: + - when: on_success variables: GOSDN_LOG: "nolog" GOSDN_CHANGE_TIMEOUT: "100ms" @@ -16,7 +18,6 @@ unit-test: script: - gotestsum --junitfile report.xml --format testname -- -short -race $(go list ./... | grep -v /forks/ | grep -v /mocks ) -v -coverprofile=coverage.out - # -short -race $(go list ./... | grep -v /forks/ | grep -v /mocks ) -v after_script: - go tool cover -func=coverage.out <<: *test @@ -30,3 +31,10 @@ controller-test: <<: *test rules: - !reference [.merge_request, rules] + +test-build: + artifacts: + when: never + script: + - GOOS=linux go build $BUILDARGS ./cmd/gosdn + <<: *test diff --git a/.gitlab/ci/.uml-autogen-ci.yml b/.gitlab/ci/.uml-autogen-ci.yml index cd7db4c9dceb8716b47f27401b940159157b26d3..adaf8c99dc09056b5183d0177e7c3e7dfaf6a5b3 100644 --- a/.gitlab/ci/.uml-autogen-ci.yml +++ b/.gitlab/ci/.uml-autogen-ci.yml @@ -1,5 +1,5 @@ goplantuml: - image: golang:$GOLANG_VERSION + image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/golang:$GOLANG_VERSION stage: .post only: - develop diff --git a/Dockerfile b/Dockerfile index 48ab0f161f61439459a792aac584ee7c82132630..b583530d460522d176b4899f774ef7e73c546f80 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ ARG GOLANG_VERSION=1.16 ARG BUILDARGS +ARG $GITLAB_PROXY -FROM golang:$GOLANG_VERSION-buster AS installer +FROM ${GITLAB_PROXY}golang:$GOLANG_VERSION-buster AS installer WORKDIR /src/gosdn COPY go.* ./ @@ -13,7 +14,7 @@ COPY . ./ RUN GOOS=linux go build $BUILDARGS ./cmd/gosdn -FROM debian:bullseye +FROM ${GITLAB_PROXY}debian:bullseye EXPOSE 8080 EXPOSE 55055 COPY --from=builder /src/gosdn/gosdn . diff --git a/Dockerfile.alpine b/Dockerfile.alpine deleted file mode 100644 index 03a059e084dcc7832d4bcc70b65666438e12009d..0000000000000000000000000000000000000000 --- a/Dockerfile.alpine +++ /dev/null @@ -1,23 +0,0 @@ -# syntax = docker/dockerfile:1.2 - -FROM golang:1.16-alpine AS builder -ARG GITLAB_USER -ARG GITLAB_TOKEN -ARG BUILDARGS -WORKDIR /src/gosdn -RUN apk add --no-cache git -RUN git config --global url."https://$GITLAB_USER:$GITLAB_TOKEN@code.fbi.h-da.de".insteadOf "https://code.fbi.h-da.de" -COPY go.* . -RUN go mod download -COPY . . -RUN --mount=type=cache,target=/root/.cache/go-build \ -GOOS=linux go build -o gosdn ./cmd/gosdn - -FROM alpine -EXPOSE 8080 -EXPOSE 55055 -COPY --from=builder /src/gosdn/gosdn . -COPY --from=builder /src/gosdn/configs ./configs - -ENTRYPOINT [ "./gosdn" ] -CMD [""] diff --git a/api/initialise_test.go b/api/initialise_test.go index c6a00cc2770e63cea87b577fe61c223e292a9c05..347a20a806d1fd027468bbf25f9481048590f8fe 100644 --- a/api/initialise_test.go +++ b/api/initialise_test.go @@ -5,11 +5,13 @@ import ( "net" "os" "testing" + "time" cpb "code.fbi.h-da.de/danet/api/go/gosdn/core" ppb "code.fbi.h-da.de/danet/api/go/gosdn/pnd" tpb "code.fbi.h-da.de/danet/api/go/gosdn/transport" + "code.fbi.h-da.de/danet/gosdn/config" "code.fbi.h-da.de/danet/gosdn/mocks" nbi "code.fbi.h-da.de/danet/gosdn/northbound/server" "code.fbi.h-da.de/danet/gosdn/nucleus" @@ -128,14 +130,12 @@ func TestMain(m *testing.M) { } func bootstrapIntegrationTest() { - if os.Getenv("GOSDN_LOG") == "nolog" { - log.SetLevel(log.PanicLevel) - } + log.SetLevel(config.LogLevel) - addr := os.Getenv("GOSDN_TEST_ENDPOINT") + addr := os.Getenv("CEOS_TEST_ENDPOINT") if addr != "" { testAddress = addr - log.Infof("GOSDN_TEST_ENDPOINT set to %v", testAddress) + log.Infof("CEOS_TEST_ENDPOINT set to %v", testAddress) } api := os.Getenv("GOSDN_TEST_API_ENDPOINT") if api != "" { diff --git a/cmd/root.go b/cmd/root.go index e7465b44fec469a0775c8437e31a6efc8aaa7713..7559bde87612fb3252578b4cf9d81bac1dd26285 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -34,6 +34,7 @@ package cmd import ( "context" "os" + "path/filepath" "code.fbi.h-da.de/danet/gosdn" @@ -80,16 +81,22 @@ func init() { rootCmd.Flags().StringVar(&csbiOrchestrstor, "csbi-orchestrator", "localhost:55056", "csbi orchestrator address") } +const ( + configHome string = "./configs" + configName string = "gosdn" + configType string = "toml" +) + // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { - viper.AddConfigPath("./configs") + viper.AddConfigPath(configHome) viper.AddConfigPath("/usr/local/etc/gosdn/") - viper.SetConfigType("toml") - viper.SetConfigName("gosdn") + viper.SetConfigType(configType) + viper.SetConfigName(configName) } viper.AutomaticEnv() // read in environment variables that match @@ -97,6 +104,8 @@ func initConfig() { // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { log.Debug("Using config file:", viper.ConfigFileUsed()) + } else { + ensureViperConfigFileExists() } viper.SetDefault("socket", ":55055") @@ -118,3 +127,28 @@ func initConfig() { log.SetReportCaller(false) } } + +func ensureFileSystemStoreExists(pathToStore string) error { + emptyString := []byte("") + err := os.WriteFile(pathToStore, emptyString, 0600) + if err != nil { + return err + } + + return nil +} + +func ensureViperConfigFileExists() { + // Viper will crash if you call 'WriteConfig()' and the file does + // not exists yet. + // Therefore we handle this case here. + // Inspired by //https://github.com/spf13/viper/issues/430#issuecomment-661945101 + configPath := filepath.Join(configHome, configName+"."+configType) + + if _, err := os.Stat(configPath); os.IsNotExist(err) { + err := ensureFileSystemStoreExists(configPath) + if err != nil { + panic(err) + } + } +} diff --git a/config.go b/config.go deleted file mode 100644 index 9e09fcc913adc38e9fc94d9f4d1a94c83c9f5316..0000000000000000000000000000000000000000 --- a/config.go +++ /dev/null @@ -1,61 +0,0 @@ -package gosdn - -import ( - "github.com/google/uuid" - "github.com/spf13/viper" -) - -// Config represents the nucleus configuration -type Config struct { - BasePndUUID uuid.UUID - BaseSouthBoundType int32 - BaseSouthBoundUUID uuid.UUID -} - -func getUUIDFromViper(viperKey string) (uuid.UUID, error) { - UUIDAsString := viper.GetString(viperKey) - if UUIDAsString == "" { - newUUID := uuid.New() - viper.Set(viperKey, newUUID.String()) - viper.WriteConfig() - - return newUUID, nil - } - - parsedUUID, err := uuid.Parse(UUIDAsString) - if err != nil { - return uuid.Nil, err - } - - return parsedUUID, nil -} - -// InitializeConfig loads the configuration -func (c *Config) InitializeConfig() error { - var err error - basePNDUUIDKey := "basePNDUUID" - baseSouthBoundTypeKey := "baseSouthBoundType" - baseSouthBoundUUIDKey := "baseSouthBoundUUID" - - basePNDUUID, err := getUUIDFromViper(basePNDUUIDKey) - if err != nil { - return err - } - - c.BasePndUUID = basePNDUUID - - baseSouthBoundUUID, err := getUUIDFromViper(baseSouthBoundUUIDKey) - if err != nil { - return err - } - - c.BaseSouthBoundUUID = baseSouthBoundUUID - - c.BaseSouthBoundType = viper.GetInt32("BaseSouthBoundType") - if c.BaseSouthBoundType != 0 { - viper.Set(baseSouthBoundTypeKey, 0) - viper.WriteConfig() - } - - return nil -} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000000000000000000000000000000000000..86e39b6872bd7cda753714360277a955b348d7f9 --- /dev/null +++ b/config/config.go @@ -0,0 +1,114 @@ +package config + +import ( + "os" + "time" + + "github.com/google/uuid" + "github.com/sirupsen/logrus" + log "github.com/sirupsen/logrus" + "github.com/spf13/viper" +) + +const ( + defaultTimeOutDuration10minutes = time.Minute * 10 + basePNDUUIDKey = "basePNDUUID" + baseSouthBoundTypeKey = "baseSouthBoundType" + baseSouthBoundUUIDKey = "baseSouthBoundUUID" + changeTimeoutKey = "GOSDN_CHANGE_TIMEOUT" +) + +// BasePndUUID is an uuid for the base PND +var BasePndUUID uuid.UUID + +// BaseSouthBoundType is the type of the base SBI +var BaseSouthBoundType int32 + +// BaseSouthBoundUUID is an uuid for the base SBI +var BaseSouthBoundUUID uuid.UUID + +// ChangeTimeout is the default timeout for a change +var ChangeTimeout time.Duration + +// LogLevel ist the default log level +var LogLevel logrus.Level + +// Init gets called on module import +func Init() { + InitializeConfig() +} + +// InitializeConfig loads the configuration +func InitializeConfig() error { + var err error + + basePNDUUIDFromViper, err := getUUIDFromViper(basePNDUUIDKey) + if err != nil { + return err + } + + BasePndUUID = basePNDUUIDFromViper + + baseSouthBoundUUIDFromViper, err := getUUIDFromViper(baseSouthBoundUUIDKey) + if err != nil { + return err + } + + BaseSouthBoundUUID = baseSouthBoundUUIDFromViper + + BaseSouthBoundType = viper.GetInt32(baseSouthBoundTypeKey) + if BaseSouthBoundType != 0 { + viper.Set(baseSouthBoundTypeKey, 0) + viper.WriteConfig() + } + + err = setChangeTimeout() + if err != nil { + return err + } + + setLogLevel() + + return nil +} + +func getUUIDFromViper(viperKey string) (uuid.UUID, error) { + UUIDAsString := viper.GetString(viperKey) + if UUIDAsString == "" { + newUUID := uuid.New() + viper.Set(viperKey, newUUID.String()) + viper.WriteConfig() + + return newUUID, nil + } + + parsedUUID, err := uuid.Parse(UUIDAsString) + if err != nil { + return uuid.Nil, err + } + + return parsedUUID, nil +} + +func setChangeTimeout() error { + e := os.Getenv(changeTimeoutKey) + if e != "" { + changeTimeout, err := time.ParseDuration(e) + if err != nil { + log.Fatal(err) + } + ChangeTimeout = changeTimeout + } else { + ChangeTimeout = time.Minute * 10 + } + + return nil +} + +func setLogLevel() { + if os.Getenv("GOSDN_LOG") == "nolog" { + LogLevel = logrus.PanicLevel + } else { + LogLevel = logrus.InfoLevel + } +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6a1afccee6a9f8fd61f98ffc1d3ef6b87da0b856 --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,63 @@ +package config + +import ( + "os" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/spf13/viper" +) + +func TestInit(t *testing.T) { + viper.SetConfigFile("./config_test.toml") + viper.Set("baseSouthBoundType", 0) + viper.Set("baseSouthBoundUUID", "bf8160d4-4659-4a1b-98fd-f409a04111eb") + viper.Set("basePNDUUID", "bf8160d4-4659-4a1b-98fd-f409a04111ec") + viper.Set("GOSDN_CHANGE_TIMEOUT", "10m") +} + +func TestUseExistingConfig(t *testing.T) { + TestInit(t) + + err := InitializeConfig() + if err != nil { + t.Error(err) + return + } + + if BasePndUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111ec" { + t.Fatalf("BasePndUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111ec. got=%s", + BasePndUUID.String()) + } + + if BaseSouthBoundUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111eb" { + t.Fatalf("BaseSouthBoundUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111eb. got=%s", + BaseSouthBoundUUID.String()) + } + + if BaseSouthBoundType != 0 { + t.Fatalf("BaseSouthBoundType is not 0. got=%d", + BaseSouthBoundType) + } + + testChangeTimeout, _ := time.ParseDuration("10m") + defaultChangeTimeout := defaultTimeOutDuration10minutes + if defaultChangeTimeout != testChangeTimeout { + t.Fatalf("ChangeTimeout is not 10ms. got=%v", + ChangeTimeout) + } + + if os.Getenv("GOSDN_LOG") == "nolog" { + if LogLevel != logrus.PanicLevel { + t.Fatalf("LogLevel is not %v. got=%v", + logrus.PanicLevel, LogLevel) + } + } else { + if LogLevel != logrus.InfoLevel { + t.Fatalf("LogLevel is not %v. got=%v", + logrus.InfoLevel, LogLevel) + } + } + +} diff --git a/config_test.go b/config_test.go deleted file mode 100644 index 89bc5f276013c73b9b89ec6d1ec74e68042f6860..0000000000000000000000000000000000000000 --- a/config_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package gosdn - -import ( - "testing" - - "github.com/spf13/viper" -) - -func Test_Init(t *testing.T) { - viper.SetConfigFile("./config_test.toml") - viper.Set("baseSouthBoundType", 0) - viper.Set("baseSouthBoundUUID", "bf8160d4-4659-4a1b-98fd-f409a04111eb") - viper.Set("basePNDUUID", "bf8160d4-4659-4a1b-98fd-f409a04111ec") -} - -func Test_UseExistingConfig(t *testing.T) { - Test_Init(t) - - testConfig := Config{} - - err := testConfig.InitializeConfig() - if err != nil { - t.Error(err) - return - } - - if testConfig.BasePndUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111ec" { - t.Fatalf("testConfig.BasePndUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111ec. got=%s", - testConfig.BasePndUUID.String()) - } - - if testConfig.BaseSouthBoundUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111eb" { - t.Fatalf("testConfig.BaseSouthBoundUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111eb. got=%s", - testConfig.BaseSouthBoundUUID.String()) - } - - if testConfig.BaseSouthBoundType != 0 { - t.Fatalf("testConfig.BaseSouthBoundType is not 0. got=%d", - testConfig.BaseSouthBoundType) - } -} diff --git a/configs/.gitkeep b/configs/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/controller.go b/controller.go index d668c1753618fe44276c3b9d6885ccb623e29bdb..748c7aa79b15161bbda1069d2d67ed730bc3b703 100644 --- a/controller.go +++ b/controller.go @@ -18,6 +18,7 @@ import ( cpb "code.fbi.h-da.de/danet/api/go/gosdn/csbi" ppb "code.fbi.h-da.de/danet/api/go/gosdn/pnd" spb "code.fbi.h-da.de/danet/api/go/gosdn/southbound" + "code.fbi.h-da.de/danet/gosdn/config" "code.fbi.h-da.de/danet/gosdn/interfaces/southbound" nbi "code.fbi.h-da.de/danet/gosdn/northbound/server" "code.fbi.h-da.de/danet/gosdn/store" @@ -61,13 +62,12 @@ func initialize() error { startHttpServer() coreLock.Unlock() - config := Config{} err := config.InitializeConfig() if err != nil { return err } - return createSouthboundInterfaces(config) + return createSouthboundInterfaces() } func startGrpc() error { @@ -98,13 +98,13 @@ func startGrpc() error { } // createSouthboundInterfaces initializes the controller with its supported SBIs -func createSouthboundInterfaces(config Config) error { +func createSouthboundInterfaces() error { sbi := nucleus.NewSBI(spb.Type(config.BaseSouthBoundType), config.BaseSouthBoundUUID) - return createPrincipalNetworkDomain(sbi, config) + return createPrincipalNetworkDomain(sbi) } // createPrincipalNetworkDomain initializes the controller with an initial PND -func createPrincipalNetworkDomain(s southbound.SouthboundInterface, config Config) error { +func createPrincipalNetworkDomain(s southbound.SouthboundInterface) error { pnd, err := nucleus.NewPND("base", "gosdn base pnd", config.BasePndUUID, s, c.csbiClient, callback) if err != nil { return err diff --git a/initialise_test.go b/initialise_test.go index d47822bbd8de7398ab5ebe30f1d5f9e8bc8bff84..bba39814b70fd1cbf9807c86baa0c024457ba733 100644 --- a/initialise_test.go +++ b/initialise_test.go @@ -4,6 +4,8 @@ import ( "os" "testing" + "code.fbi.h-da.de/danet/gosdn/config" + "github.com/google/uuid" log "github.com/sirupsen/logrus" ) @@ -17,10 +19,8 @@ var cuid uuid.UUID func TestMain(m *testing.M) { log.SetReportCaller(true) + log.SetLevel(config.LogLevel) - if os.Getenv("GOSDN_LOG") == "nolog" { - log.SetLevel(log.PanicLevel) - } readTestUUIDs() os.Exit(m.Run()) } diff --git a/nucleus/change_test.go b/nucleus/change_test.go index fa4cf5b9c96da4a09a486ae00de080dfe8f90e04..6fdff64fc223abb8adcd43a0192ca9a74185f804 100644 --- a/nucleus/change_test.go +++ b/nucleus/change_test.go @@ -8,6 +8,7 @@ import ( "time" ppb "code.fbi.h-da.de/danet/api/go/gosdn/pnd" + "code.fbi.h-da.de/danet/gosdn/config" "github.com/google/uuid" "github.com/openconfig/ygot/exampleoc" "github.com/openconfig/ygot/ygot" @@ -61,7 +62,7 @@ func TestChange_CommitRollback(t *testing.T) { if err := c.Commit(); (err != nil) != wantErr { t.Errorf("Commit() error = %v, wantErr %v", err, wantErr) } - time.Sleep(time.Millisecond * 200) + time.Sleep(config.ChangeTimeout) }() got := <-callback if !reflect.DeepEqual(got, want) { @@ -103,7 +104,7 @@ func TestChange_CommitRollbackError(t *testing.T) { if err := c.Commit(); (err != nil) != wantErr { t.Errorf("Commit() error = %v, wantErr %v", err, wantErr) } - time.Sleep(time.Millisecond * 200) + time.Sleep(config.ChangeTimeout) }() got := <-c.errChan if !reflect.DeepEqual(got, want) { diff --git a/nucleus/southbound.go b/nucleus/southbound.go index 9de3b15fe408b8bd73173dda0c067b34a70accbf..a49f1c3d99196acefdd17c131b1cbf69b587a737 100644 --- a/nucleus/southbound.go +++ b/nucleus/southbound.go @@ -114,7 +114,10 @@ func unmarshal(schema *ytypes.Schema, bytes []byte, fields []string, goStruct yg return err } ygot.PruneEmptyBranches(validatedDeepCopy) - return ygot.MergeStructInto(goStruct, validatedDeepCopy) + + opts := []ygot.MergeOpt{&ygot.MergeOverwriteExistingFields{}} + + return ygot.MergeStructInto(goStruct, validatedDeepCopy, opts...) } // getField traverses the GoStruct and returns the field that represents the diff --git a/test/integration/nucleusIntegration_test.go b/test/integration/nucleusIntegration_test.go index 4e2ec7a5a8d50a068cfb38a33901b2e4056d6a24..cf7b86936827bf78862ff2f9d1ede030cab5241d 100644 --- a/test/integration/nucleusIntegration_test.go +++ b/test/integration/nucleusIntegration_test.go @@ -45,10 +45,10 @@ func testSetupIntegration() { log.SetLevel(log.PanicLevel) } - addr := os.Getenv("GOSDN_TEST_ENDPOINT") + addr := os.Getenv("CEOS_TEST_ENDPOINT") if addr != "" { testAddress = addr - log.Infof("GOSDN_TEST_ENDPOINT set to %v", testAddress) + log.Infof("CEOS_TEST_ENDPOINT set to %v", testAddress) } u := os.Getenv("GOSDN_TEST_USER") if u != "" {