storj/internal/version/version.go
Stefan Benten 2cf86703a3
Add Versioning Server (#1576)
* Initial Webserver Draft for Version Controlling

* Rename type to avoid confusion

* Move Function Calls into Version Package

* Fix Linting and Language Typos

* Fix Linting and Spelling Mistakes

* Include Copyright

* Include Copyright

* Adjust Version-Control Server to return list of Versions

* Linting

* Improve Request Handling and Readability

* Add Configuration File Option
Add Systemd Service file

* Add Logging to File

* Smaller Changes

* Add Semantic Versioning and refuses outdated Software from Startup (#1612)

* implements internal Semantic Version library

* adds version logging + reporting to process

* Advance SemVer struct for easier handling

* Add Accepted Version Store

* Fix Function

* Restructure

* Type Conversion

* Handle Version String properly

* Add Note about array index

* Set temporary Default Version

* Add Copyright

* Adding Version to Dashboard

* Adding Version Info Log

* Renaming and adding CheckerProcess

* Iteration Sync

* Iteration V2

* linting

* made LogAndReportVersion a go routine

* Refactor to Go Routine

* Add Context to Go Routine and allow Operation if Lookup to Control Server fails

* Handle Unmarshal properly

* Linting

* Relocate Version Checks

* Relocating Version Check and specified default Version for now

* Linting Error Prevention

* Refuse Startup on outdated Version

* Add Startup Check Function

* Straighten Logging

* Dont force Shutdown if --dev flag is set

* Create full Service/Peer Structure for ControlServer

* Linting

* Straighting Naming

* Finish VersionControl Service Layout

* Improve Error Handling

* Change Listening Address

* Move Checker Function

* Remove VersionControl Peer

* Linting

* Linting

* Create VersionClient Service

* Renaming

* Add Version Client to Peer Definitions

* Linting and Renaming

* Linting

* Remove Transport Checks for now

* Move to Client Side Flag

* Remove check

* Linting

* Transport Client Version Intro

* Adding Version Client to Transport Client

* Add missing parameter

* Adding Version Check, to set Allowed = true

* Set Default to true, testing

* Restructuring Code

* Uplink Changes

* Add more proper Defaults

* Renaming of Version struct

* Dont pass Service use Pointer

* Set Defaults for Versioning Checks

* Put HTTP Server in go routine

* Add Versioncontrol to Storj-Sim

* Testplanet Fixes

* Linting

* Add Error Handling and new Server Struct

* Move Lock slightly

* Reduce Race Potentials

* Remove unnecessary files

* Linting

* Add Proper Transport Handling

* small fixes

* add fence for allowed check

* Add Startup Version Check and Service Naming

* make errormessage private

* Add Comments about VersionedClient

* Linting

* Remove Checks that refuse outgoing connections

* Remove release cmd

* Add Release Script

* Linting

* Update to use correct Values

* Move vars private and set minimum default versions for testing builds

* Remove VersionedClient

* Better Error Handling and naked return removal

* Straighten the Regex and string conversion

* Change Check to allows testplanet and storj-sim to run without the
need to pass an LDFlag

* Cosmetic Change to Dashboard

* Cleanup Returns and remove commented code

* Remove Version Check if no build options are passed in

* Pass in Config Values instead of Pointers

* Handle missed Error

* Update Endpoint URL

* Change Type of Release Flag

* Add additional Logging

* Remove Versions Logging of other Services

* minor fixes

Change-Id: I5cc04a410ea6b2008d14dffd63eb5f36dd348a8b
2019-04-03 21:13:39 +02:00

157 lines
3.7 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package version
import (
"encoding/json"
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"time"
monkit "gopkg.in/spacemonkeygo/monkit.v2"
)
var (
mon = monkit.Package()
// the following fields are set by linker flags. if any of them
// are set and fail to parse, the program will fail to start
buildTimestamp string // unix seconds since epoch
buildCommitHash string
buildVersion string // semantic version format
buildRelease string // true/false
// Build is a struct containing all relevant build information associated with the binary
Build Info
)
// Info is the versioning information for a binary
type Info struct {
Timestamp time.Time `json:"timestamp,omitempty"`
CommitHash string `json:"commitHash,omitempty"`
Version SemVer `json:"version"`
Release bool `json:"release,omitempty"`
}
// SemVer represents a semantic version
type SemVer struct {
Major int64 `json:"major"`
Minor int64 `json:"minor"`
Patch int64 `json:"patch"`
}
// AllowedVersions provides a list of SemVer per Service
type AllowedVersions struct {
Bootstrap []SemVer
Satellite []SemVer
Storagenode []SemVer
Uplink []SemVer
Gateway []SemVer
}
// SemVerRegex is the regular expression used to parse a semantic version.
// https://github.com/Masterminds/semver/blob/master/LICENSE.txt
const SemVerRegex string = `v?([0-9]+)\.([0-9]+)\.([0-9]+)`
var versionRegex = regexp.MustCompile("^" + SemVerRegex + "$")
// NewSemVer parses a given version and returns an instance of SemVer or
// an error if unable to parse the version.
func NewSemVer(v string) (*SemVer, error) {
m := versionRegex.FindStringSubmatch(v)
if m == nil {
return nil, errors.New("invalid semantic version for build")
}
sv := SemVer{}
var err error
// first entry of m is the entire version string
sv.Major, err = strconv.ParseInt(m[1], 10, 64)
if err != nil {
return nil, err
}
sv.Minor, err = strconv.ParseInt(m[2], 10, 64)
if err != nil {
return nil, err
}
sv.Patch, err = strconv.ParseInt(m[3], 10, 64)
if err != nil {
return nil, err
}
return &sv, nil
}
// String converts the SemVer struct to a more easy to handle string
func (sem *SemVer) String() (version string) {
return fmt.Sprintf("v%d.%d.%d", sem.Major, sem.Minor, sem.Patch)
}
// New creates Version_Info from a json byte array
func New(data []byte) (v Info, err error) {
err = json.Unmarshal(data, &v)
return v, err
}
// Marshal converts the existing Version Info to any json byte array
func (v Info) Marshal() (data []byte, err error) {
data, err = json.Marshal(v)
return
}
// containsVersion compares the allowed version array against the passed version
func containsVersion(all []SemVer, x SemVer) bool {
for _, n := range all {
if x == n {
return true
}
}
return false
}
// StrToSemVerList converts a list of versions to a list of SemVer
func StrToSemVerList(serviceVersions []string) (versions []SemVer, err error) {
for _, subversion := range serviceVersions {
sVer, err := NewSemVer(subversion)
if err != nil {
return nil, err
}
versions = append(versions, *sVer)
}
return versions, err
}
func init() {
if buildVersion == "" && buildTimestamp == "" && buildCommitHash == "" && buildRelease == "" {
return
}
timestamp, err := strconv.ParseInt(buildTimestamp, 10, 64)
if err != nil {
panic(fmt.Sprintf("invalid timestamp: %v", err))
}
Build = Info{
Timestamp: time.Unix(timestamp, 0),
CommitHash: buildCommitHash,
Release: strings.ToLower(buildRelease) == "true",
}
sv, err := NewSemVer(buildVersion)
if err != nil {
panic(err)
}
Build.Version = *sv
if Build.Timestamp.Unix() == 0 || Build.CommitHash == "" {
Build.Release = false
}
}