Skip to content
Snippets Groups Projects
Commit e9d73c52 authored by Fabian Seidl's avatar Fabian Seidl
Browse files

Merge branch 'develop' into...

Merge branch 'develop' into 248-error-handling-in-event-publishing-via-entity-services-could-be-improved
parents 0a2203ec 9212f3ff
No related branches found
No related tags found
1 merge request!370Resolve "Error handling in event publishing via entity services could be improved"
Pipeline #111652 passed
This commit is part of merge request !370. Comments created here will be created in the context of that merge request.
......@@ -59,10 +59,7 @@ var loginCmd = &cobra.Command{
// log out to remove active session in case an user is already logged in
if userToken != "" {
_, err := api.Logout(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), nbUserName)
if err != nil {
pterm.Error.Println("error logging out active user", err)
}
_, _ = api.Logout(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), nbUserName)
}
// TODO: maybe add credentials in context instead of context.TODO()
......
......@@ -100,7 +100,7 @@ func initConfig() {
} else {
env := config.DetermineConfigEnvironment()
log.Infof("environment is %s\n", env)
log.Debugf("environment is %s\n", env)
viper.AddConfigPath(configHome)
viper.AddConfigPath("/usr/local/etc/gosdn/")
......
package cmd
import (
"fmt"
"code.fbi.h-da.de/danet/gosdn/controller/version"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
// version represents the version command.
var versionCmd = &cobra.Command{
Use: "version",
Short: "returns information about the controllers version",
Long: `Version allows the user to access version and build information
about the current binary.`,
RunE: func(cmd *cobra.Command, args []string) error {
log.SetFormatter(&log.TextFormatter{
DisableQuote: true,
})
v, err := version.NewVersion()
if err != nil {
log.Error(err)
}
fmt.Println(v.String())
return nil
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}
package version
import (
"fmt"
"runtime/debug"
"strconv"
"strings"
"time"
)
var (
// The versionString is provided through ldflags while building. This
// variable should only be set through ldflags!
// Defaults to `0.0.0`.
versionString = "0.0.0"
)
// BuildInformation contains additional information about the build. The information
// is taken from `debug.ReadBuildInfo`.
type BuildInformation struct {
// goos describes the os the binary is built for.
goos string
// goarch describes the architecture the binary is built for.
goarch string
// revision is a reference to the last git commit the binary is based on.
revision string
// time is the timestamp of the last git commit the binary is based on.
time time.Time
// modified returns true if the build is modified and contains additional
// changes from the last commit - a so called dirty build.
modified bool
}
// Version describes the current version of the goSDN controller and contains
// additional build information.
type Version struct {
major int
minor int
patch int
BuildInformation
}
// NewVersion creates a new Version from the versionString, provided via
// ldflags while running `go build`. If no version information is provided
// through out the build process a default value is used.
//
// Additional build information is gathered with the help of
// `debug.ReadBuildInfo` and is added to the Version.
func NewVersion() (*Version, error) {
buildInfo, ok := debug.ReadBuildInfo()
if !ok {
return nil, fmt.Errorf("Failed reading the binaries build information")
}
parsedVersion, err := parseVersionString(versionString)
if err != nil {
return nil, fmt.Errorf("Could not parse version string: %w", err)
}
version := &Version{
major: parsedVersion[0],
minor: parsedVersion[1],
patch: parsedVersion[2],
}
for _, bSetting := range buildInfo.Settings {
switch bSetting.Key {
case "GOOS":
version.goos = bSetting.Value
case "GOARCH":
version.goarch = bSetting.Value
case "vcs.revision":
version.revision = bSetting.Value
case "vcs.time":
parsedTime, _ := time.Parse(time.RFC3339, bSetting.Value)
version.time = parsedTime
case "vcs.modified":
version.modified = bSetting.Value == "true"
}
}
return version, nil
}
func (v *Version) String() string {
return fmt.Sprintf(
`Version: %d.%d.%d
Build Information:
- GOOS: %s
- GOARCH: %s
- Revision: %s
- Time: %s
- Modified (dirty): %t`,
v.major, v.minor, v.patch, v.goos, v.goarch, v.revision, v.time.String(), v.modified,
)
}
// Compare compares the provided version with the current version. Some of the
// build information is included in the comparison. This means that revision,
// time and the modified values are compared aswell.
//
// Returns 0, -1, or 1 based on the fact if the version is equal, smaller or
// larger than the incoming version.
// If one of the versions is modified then a comparison is not possible, since
// it cannot be said with certainty that the two versions are the same. In this
// case a -2 is returned.
func (v *Version) Compare(toCompare *Version) int {
if v.modified || toCompare.modified {
return -2
}
// compare the major segment.
if c := compareVersionSegment(v.major, toCompare.major); c != 0 {
return c
}
// compare the minor segment.
if c := compareVersionSegment(v.minor, toCompare.minor); c != 0 {
return c
}
// compare the patch segment.
if c := compareVersionSegment(v.patch, toCompare.patch); c != 0 {
return c
}
// basic version is the same; now the commit information is compared.
if v.revision != toCompare.revision {
if v.time.Before(toCompare.time) {
return -1
}
return 1
}
return 0
}
// compareVersionSegment is a helper function that allows to compare version
// segments like, e.g. major, minor and patch between two versions.
//
// Left describes the segment of the version that should be compared against
// and right describes the incoming version.
//
// The function returns 0, -1, or 1 based on the fact if the version segment
// to be compared against is equal, smaller or larger than the incoming version
// segment.
func compareVersionSegment(left, right int) int {
if left < right {
return -1
}
if left > right {
return 1
}
return 0
}
// parseVersionString is a helper function that parses the given string into
// three integers: major, minor and patch. The integers are returned as an
// array of integers in that respective order.
func parseVersionString(s string) ([]int, error) {
versionSegments := strings.SplitN(s, ".", 3)
res := make([]int, 3)
for i, versionSegment := range versionSegments {
versionSegmentAsInt, err := strconv.ParseInt(versionSegment, 10, 64)
if err != nil {
return nil, err
}
res[i] = int(versionSegmentAsInt)
}
return res, nil
}
package version
import (
"fmt"
"testing"
"time"
"github.com/google/go-cmp/cmp"
)
func Test_version_NewVersion(t *testing.T) {
// custom options for comparer
opts := cmp.Options{
cmp.Comparer(func(left, right *Version) bool {
if left == nil && right == nil {
return true
}
if left.major == right.major &&
left.minor == right.minor &&
left.patch == right.patch {
return true
}
return false
}),
}
type args struct {
versionString string
}
tests := []struct {
name string
args args
want *Version
wantErr bool
}{
{
name: "default",
args: args{},
want: &Version{
major: 0,
minor: 0,
patch: 0,
BuildInformation: BuildInformation{},
},
wantErr: false,
},
{
name: "faulty version string",
args: args{
versionString: "faulty.version.string",
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// This is not run in parallel since we change the versionString
// and this would therefore result in a data race.
//
// versionString is and should only be touched through ldflags with
// `go build`.
if tt.name != "default" {
versionString = tt.args.versionString
}
got, err := NewVersion()
if (err != nil) != tt.wantErr {
t.Errorf("NewVersion() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !cmp.Equal(got, tt.want, opts...) {
t.Errorf("NewVersion() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_version_Compare(t *testing.T) {
timeNormal, err := time.Parse(time.RFC3339, "2022-08-19T11:11:02+00:00")
if err != nil {
t.Errorf("Compare() error = %v", err)
}
timeBefore, err := time.Parse(time.RFC3339, "2022-08-18T11:11:02+00:00")
if err != nil {
t.Errorf("Compare() error = %v", err)
}
timeAfter, err := time.Parse(time.RFC3339, "2022-08-22T11:11:02+00:00")
if err != nil {
t.Errorf("Compare() error = %v", err)
}
v := &Version{
major: 1,
minor: 3,
patch: 101,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
}
type args struct {
inputVersion *Version
}
tests := []struct {
name string
args args
want int
}{
{
name: "input version is equal",
args: args{
inputVersion: &Version{
major: 1,
minor: 3,
patch: 101,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
},
},
want: 0,
},
{
name: "input version is smaller based on major",
args: args{
inputVersion: &Version{
major: 0,
minor: 0,
patch: 101,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
},
},
want: 1,
},
{
name: "input version is smaller based on minor",
args: args{
inputVersion: &Version{
major: 1,
minor: 0,
patch: 101,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
},
},
want: 1,
},
{
name: "input version is smaller based on patch",
args: args{
inputVersion: &Version{
major: 1,
minor: 3,
patch: 78,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
},
},
want: 1,
},
{
name: "input version is smaller based on commit",
args: args{
inputVersion: &Version{
major: 1,
minor: 3,
patch: 101,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "14379478a8c56269dd59419d04c9080c1103174d",
time: timeBefore,
modified: false,
},
},
},
want: 1,
},
{
name: "input version is larger based on major",
args: args{
inputVersion: &Version{
major: 2,
minor: 3,
patch: 78,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
},
},
want: -1,
},
{
name: "input version is larger based on minor",
args: args{
inputVersion: &Version{
major: 1,
minor: 4,
patch: 78,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
},
},
want: -1,
},
{
name: "input version is larger based on patch",
args: args{
inputVersion: &Version{
major: 1,
minor: 3,
patch: 103,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNormal,
modified: false,
},
},
},
want: -1,
},
{
name: "input version is larger based on commit",
args: args{
inputVersion: &Version{
major: 1,
minor: 3,
patch: 101,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "14379478a8c56269dd59419d04c9080c1103174d",
time: timeAfter,
modified: false,
},
},
},
want: -1,
},
{
name: "one of the versions is modified",
args: args{
inputVersion: &Version{
BuildInformation: BuildInformation{
modified: true,
},
},
},
want: -2,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := v.Compare(tt.args.inputVersion)
if !cmp.Equal(got, tt.want) {
t.Errorf("Compare() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_version_String(t *testing.T) {
timeNow := time.Now()
v := &Version{
major: 1,
minor: 3,
patch: 101,
BuildInformation: BuildInformation{
goos: "linux",
goarch: "amd64",
revision: "34979478a8c56269dd59419d04d9080c1103174d",
time: timeNow,
modified: false,
},
}
tests := []struct {
name string
want string
}{
{
name: "default",
want: fmt.Sprintf(`Version: 1.3.101
Build Information:
- GOOS: linux
- GOARCH: amd64
- Revision: 34979478a8c56269dd59419d04d9080c1103174d
- Time: %s
- Modified (dirty): false`, timeNow.String()),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := v.String()
if !cmp.Equal(got, tt.want) {
t.Errorf("String() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_version_compareVersionSegment(t *testing.T) {
type args struct {
left, right int
}
tests := []struct {
name string
args args
want int
}{
{
name: "left is smaller && right is larger",
args: args{
left: 5,
right: 8,
},
want: -1,
},
{
name: "left is larger && right is smaller",
args: args{
left: 9,
right: 3,
},
want: 1,
},
{
name: "left and right are equal",
args: args{
left: 4,
right: 4,
},
want: 0,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := compareVersionSegment(tt.args.left, tt.args.right)
if !cmp.Equal(got, tt.want) {
t.Errorf("compareVersionSegment() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_version_parseVersionString(t *testing.T) {
type args struct {
input string
}
tests := []struct {
name string
args args
want []int
wantErr bool
}{
{
name: "default",
args: args{
input: "1.0.4",
},
want: []int{1, 0, 4},
wantErr: false,
},
{
name: "too many values in version string",
args: args{
input: "1.0.4.259",
},
want: nil,
wantErr: true,
},
{
name: "faulty version string - no numbers",
args: args{
input: "this is wrong",
},
want: nil,
wantErr: true,
},
{
name: "faulty version string - wrong delimiter",
args: args{
input: "1-2-187",
},
want: nil,
wantErr: true,
},
{
name: "faulty version string - mixed",
args: args{
input: "1.abc.283",
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := parseVersionString(tt.args.input)
if (err != nil) != tt.wantErr {
t.Errorf("parseVersionString() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !cmp.Equal(got, tt.want) {
t.Errorf("parseVersionString() got = %v, want %v", got, tt.want)
}
})
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment