Skip to content

Commit

Permalink
Merge pull request #70 from stefannica/version
Browse files Browse the repository at this point in the history
Add version information to server and CLI
  • Loading branch information
stefannica authored Jun 2, 2021
2 parents fffbf27 + e087cf8 commit 689e963
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 8 deletions.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Build the fuseml_core binary
FROM golang:1.16 as builder

ARG LDFLAGS="-w -s"

WORKDIR /workspace

# Copy the Go Modules manifests
Expand All @@ -16,7 +18,7 @@ COPY cmd/ cmd/
COPY pkg/ pkg/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -ldflags '-s -w' -o fuseml_core ./cmd/fuseml_core
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -ldflags "$LDFLAGS" -o fuseml_core ./cmd/fuseml_core

# Use docker scratch as minimal base image to package FuseML binaries
# Refer to https://docs.docker.com/develop/develop-images/baseimages/#create-a-simple-parent-image-using-scratch
Expand Down
35 changes: 33 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,38 @@ endif
GOOS:=$(shell go env GOOS)
GOARCH:=$(shell go env GOARCH)

GO_LDFLAGS:=-ldflags '-s -w'
LDFLAGS:= -w -s

PKG_PATH=github.com/fuseml/fuseml-core/pkg

GIT_COMMIT = $(shell git rev-parse --short=8 HEAD)
GIT_BRANCH = $(shell git rev-parse --abbrev-ref HEAD|grep -v HEAD)
GIT_TAG = $(shell git describe --tags --abbrev=0 --exact-match 2>/dev/null)
BUILD_DATE = $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')

ifdef VERSION
BINARY_VERSION = $(VERSION)
else
# Use `dev` as a default version value when compiling in the main branch
ifeq ($(GIT_BRANCH),main)
BINARY_VERSION = dev
# Use the branch name as a default version value when compiling in another branch
else
BINARY_VERSION = $(GIT_BRANCH)
endif
ifneq ($(GIT_TAG),)
BINARY_VERSION = $(GIT_TAG)
else
endif
endif

LDFLAGS += -X $(PKG_PATH)/version.GitCommit=$(GIT_COMMIT)
LDFLAGS += -X $(PKG_PATH)/version.BuildDate=$(BUILD_DATE)
ifneq ($(BINARY_VERSION),)
LDFLAGS += -X $(PKG_PATH)/version.Version=$(BINARY_VERSION)
endif

GO_LDFLAGS:=-ldflags '$(LDFLAGS)'

all: fuseml

Expand Down Expand Up @@ -103,7 +134,7 @@ deps:

# Build the docker image
docker-build: test
docker build . -t ${IMG}
docker build . -t ${IMG} --build-arg LDFLAGS="$(LDFLAGS)"

# Push the docker image
docker-push:
Expand Down
11 changes: 10 additions & 1 deletion cmd/fuseml_core/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import (
codesetsvr "github.com/fuseml/fuseml-core/gen/http/codeset/server"
openapisvr "github.com/fuseml/fuseml-core/gen/http/openapi/server"
runnablesvr "github.com/fuseml/fuseml-core/gen/http/runnable/server"
versionsvr "github.com/fuseml/fuseml-core/gen/http/version/server"
workflowsvr "github.com/fuseml/fuseml-core/gen/http/workflow/server"
runnable "github.com/fuseml/fuseml-core/gen/runnable"
"github.com/fuseml/fuseml-core/gen/version"
workflow "github.com/fuseml/fuseml-core/gen/workflow"

"github.com/goccy/go-yaml"
Expand All @@ -29,7 +31,7 @@ import (

// handleHTTPServer starts configures and starts a HTTP server on the given
// URL. It shuts down the server if any error is received in the error channel.
func handleHTTPServer(ctx context.Context, u *url.URL, runnableEndpoints *runnable.Endpoints, codesetEndpoints *codeset.Endpoints, workflowEndpoints *workflow.Endpoints, applicationEndpoints *application.Endpoints, wg *sync.WaitGroup, errc chan error, logger *log.Logger, debug bool) {
func handleHTTPServer(ctx context.Context, u *url.URL, versionEndpoints *version.Endpoints, runnableEndpoints *runnable.Endpoints, codesetEndpoints *codeset.Endpoints, workflowEndpoints *workflow.Endpoints, applicationEndpoints *application.Endpoints, wg *sync.WaitGroup, errc chan error, logger *log.Logger, debug bool) {
// Setup goa log adapter.
var (
adapter middleware.Logger
Expand Down Expand Up @@ -59,6 +61,7 @@ func handleHTTPServer(ctx context.Context, u *url.URL, runnableEndpoints *runnab
// the service input and output data structures to HTTP requests and
// responses.
var (
versionServer *versionsvr.Server
applicationServer *applicationsvr.Server
runnableServer *runnablesvr.Server
codesetServer *codesetsvr.Server
Expand All @@ -67,13 +70,15 @@ func handleHTTPServer(ctx context.Context, u *url.URL, runnableEndpoints *runnab
)
{
eh := errorHandler(logger)
versionServer = versionsvr.New(versionEndpoints, mux, dec, enc, eh, nil)
applicationServer = applicationsvr.New(applicationEndpoints, mux, dec, enc, eh, nil)
runnableServer = runnablesvr.New(runnableEndpoints, mux, dec, enc, eh, nil)
codesetServer = codesetsvr.New(codesetEndpoints, mux, dec, enc, eh, nil)
openapiServer = openapisvr.New(nil, mux, dec, enc, eh, nil)
workflowServer = workflowsvr.New(workflowEndpoints, mux, dec, enc, eh, nil)
if debug {
servers := goahttp.Servers{
versionServer,
applicationServer,
runnableServer,
codesetServer,
Expand All @@ -84,6 +89,7 @@ func handleHTTPServer(ctx context.Context, u *url.URL, runnableEndpoints *runnab
}
}
// Configure the mux.
versionsvr.Mount(mux, versionServer)
applicationsvr.Mount(mux, applicationServer)
runnablesvr.Mount(mux, runnableServer)
codesetsvr.Mount(mux, codesetServer)
Expand All @@ -101,6 +107,9 @@ func handleHTTPServer(ctx context.Context, u *url.URL, runnableEndpoints *runnab
// Start HTTP server using default configuration, change the code to
// configure the server as required by your service.
srv := &http.Server{Addr: u.Host, Handler: handler}
for _, m := range versionServer.Mounts {
logger.Printf("HTTP %q mounted on %s %s", m.Method, m.Verb, m.Pattern)
}
for _, m := range applicationServer.Mounts {
logger.Printf("HTTP %q mounted on %s %s", m.Method, m.Verb, m.Pattern)
}
Expand Down
14 changes: 12 additions & 2 deletions cmd/fuseml_core/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import (
"github.com/fuseml/fuseml-core/gen/application"
"github.com/fuseml/fuseml-core/gen/codeset"
"github.com/fuseml/fuseml-core/gen/runnable"
"github.com/fuseml/fuseml-core/gen/version"
"github.com/fuseml/fuseml-core/gen/workflow"
"github.com/fuseml/fuseml-core/pkg/core"
"github.com/fuseml/fuseml-core/pkg/core/gitea"
"github.com/fuseml/fuseml-core/pkg/svc"
ver "github.com/fuseml/fuseml-core/pkg/version"
)

func main() {
Expand All @@ -42,6 +44,8 @@ func main() {
logger = log.New(os.Stderr, "[fuseml] ", log.Ltime)
}

logger.Printf("version: %s", ver.GetInfoStr())

gitAdmin, err := gitea.NewAdminClient(logger)
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to initialize Gitea admin client: ", err.Error())
Expand All @@ -50,12 +54,14 @@ func main() {

// Initialize the services.
var (
versionSvc version.Service
applicationSvc application.Service
runnableSvc runnable.Service
codesetSvc codeset.Service
workflowSvc workflow.Service
)
{
versionSvc = svc.NewVersionService(logger)
codesetStore := core.NewGitCodesetStore(gitAdmin)
applicationSvc = svc.NewApplicationService(logger, core.NewApplicationStore())
runnableSvc = svc.NewRunnableService(logger, core.NewRunnableStore())
Expand All @@ -70,12 +76,14 @@ func main() {
// Wrap the services in endpoints that can be invoked from other services
// potentially running in different processes.
var (
versionEndpoints *version.Endpoints
applicationEndpoints *application.Endpoints
runnableEndpoints *runnable.Endpoints
codesetEndpoints *codeset.Endpoints
workflowEndpoints *workflow.Endpoints
)
{
versionEndpoints = version.NewEndpoints(versionSvc)
applicationEndpoints = application.NewEndpoints(applicationSvc)
runnableEndpoints = runnable.NewEndpoints(runnableSvc)
codesetEndpoints = codeset.NewEndpoints(codesetSvc)
Expand Down Expand Up @@ -123,7 +131,8 @@ func main() {
} else if u.Port() == "" {
u.Host = net.JoinHostPort(u.Host, "80")
}
handleHTTPServer(ctx, u, runnableEndpoints, codesetEndpoints, workflowEndpoints, applicationEndpoints, &wg, errc, logger, *dbgF)
handleHTTPServer(ctx, u, versionEndpoints, runnableEndpoints, codesetEndpoints, workflowEndpoints, applicationEndpoints,
&wg, errc, logger, *dbgF)
}

{
Expand Down Expand Up @@ -176,7 +185,8 @@ func main() {
} else if u.Port() == "" {
u.Host = net.JoinHostPort(u.Host, "80")
}
handleHTTPServer(ctx, u, runnableEndpoints, codesetEndpoints, workflowEndpoints, applicationEndpoints, &wg, errc, logger, *dbgF)
handleHTTPServer(ctx, u, versionEndpoints, runnableEndpoints, codesetEndpoints, workflowEndpoints, applicationEndpoints,
&wg, errc, logger, *dbgF)
}

{
Expand Down
47 changes: 47 additions & 0 deletions design/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package design

import (
. "goa.design/goa/v3/dsl"
)

var _ = Service("version", func() {
Description("The version service displays version information.")

Method("get", func() {
Description("Retrieve version information.")

Result(VersionInfo)

HTTP(func() {
GET("/version")
Response(StatusOK)
})

GRPC(func() {
Response(CodeOK)
})
})
})

// VersionInfo describes server version information
var VersionInfo = Type("VersionInfo", func() {

Field(1, "version", String, "The server version", func() {
Example("v1.0")
})
Field(2, "gitCommit", String, "The git commit corresponding to the running server version", func() {
Example("4833d673")
})
Field(3, "buildDate", String, "The date the server binary was built", func() {
Example("2021-06-02T10:21:03Z")
})
Field(4, "golangVersion", String, "The GO version used to build the binary", func() {
Example("go1.16.0")
})
Field(5, "golangCompiler", String, "The GO compiler used to build the binary", func() {
Example("gc")
})
Field(6, "platform", String, "The platform where the server is running", func() {
Example("linux/amd64")
})
})
2 changes: 2 additions & 0 deletions pkg/cli/client/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Clients struct {
ApplicationClient *applicationc.Client
WorkflowClient *WorkflowClient
RunnableClient *runnablec.Client
VersionClient *VersionClient
}

// InitializeClients initializes a list of fuseml clients based on global configuration parameters
Expand Down Expand Up @@ -53,6 +54,7 @@ func (c *Clients) InitializeClients(URL string, timeout int, verbose bool) error
c.ApplicationClient = applicationc.NewClient(scheme, host, doer, encoder, decoder, verbose)
c.WorkflowClient = NewWorkflowClient(scheme, host, doer, encoder, decoder, verbose)
c.RunnableClient = runnablec.NewClient(scheme, host, doer, encoder, decoder, verbose)
c.VersionClient = NewVersionClient(scheme, host, doer, encoder, decoder, verbose)

return nil
}
Expand Down
33 changes: 33 additions & 0 deletions pkg/cli/client/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package client

import (
"context"
"net/http"

goahttp "goa.design/goa/v3/http"

versionc "github.com/fuseml/fuseml-core/gen/http/version/client"
"github.com/fuseml/fuseml-core/gen/version"
)

// VersionClient holds a client for Version
type VersionClient struct {
c *versionc.Client
}

// NewVersionClient initializes a VersionClient
func NewVersionClient(scheme string, host string, doer goahttp.Doer, encoder func(*http.Request) goahttp.Encoder,
decoder func(*http.Response) goahttp.Decoder, verbose bool) *VersionClient {
vc := &VersionClient{versionc.NewClient(scheme, host, doer, encoder, decoder, verbose)}
return vc
}

// Get version information.
func (vc *VersionClient) Get() (*version.VersionInfo, error) {
response, err := vc.c.Get()(context.Background(), nil)
if err != nil {
return nil, err
}

return response.(*version.VersionInfo), nil
}
2 changes: 2 additions & 0 deletions pkg/cli/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/fuseml/fuseml-core/pkg/cli/codeset"
"github.com/fuseml/fuseml-core/pkg/cli/common"
"github.com/fuseml/fuseml-core/pkg/cli/runnable"
"github.com/fuseml/fuseml-core/pkg/cli/version"
"github.com/fuseml/fuseml-core/pkg/cli/workflow"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand Down Expand Up @@ -42,6 +43,7 @@ func NewCmdRoot() *cobra.Command {
pf.BoolVarP(&o.Verbose, "verbose", "v", false, "(FUSEML_VERBOSE) print verbose information, such as HTTP request and response details")
viper.BindEnv("verbose", "FUSEML_VERBOSE")

cmd.AddCommand(version.NewCmdVersion(o))
cmd.AddCommand(codeset.NewCmdCodeset(o))
cmd.AddCommand(runnable.NewCmdRunnable(o))
cmd.AddCommand(workflow.NewCmdWorkflow(o))
Expand Down
2 changes: 0 additions & 2 deletions pkg/cli/common/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package common
import "fmt"

const (
// Version is the CLI version
Version = "0.1"
// ConfigFileName is the name of the FuseML configuration file (without extension)
ConfigFileName = "config"
// ConfigHomeSubdir is the subdirectory where the FuseML configuration files is located
Expand Down
68 changes: 68 additions & 0 deletions pkg/cli/version/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package version

import (
"fmt"
"os"

versionc "github.com/fuseml/fuseml-core/gen/version"
"github.com/fuseml/fuseml-core/pkg/cli/client"
"github.com/fuseml/fuseml-core/pkg/cli/common"
"github.com/fuseml/fuseml-core/pkg/version"

"github.com/spf13/cobra"
)

// versionOptions holds the options for the 'version' sub command
type versionOptions struct {
client.Clients
global *common.GlobalOptions
format *common.FormattingOptions
}

// newVersionOptions initializes a versionOptions struct
func newVersionOptions(gOpt *common.GlobalOptions) *versionOptions {
res := &versionOptions{global: gOpt}
res.format = common.NewSingleValueFormattingOptions()
return res
}

// NewCmdVersion creates and returns the cobra command for the `version` CLI command
func NewCmdVersion(gOpt *common.GlobalOptions) *cobra.Command {

o := newVersionOptions(gOpt)

cmd := &cobra.Command{
Use: "version",
Short: "display version information",
Long: `Display version information about the CLI and server`,
Run: func(cmd *cobra.Command, args []string) {
common.CheckErr(o.run())
},
Args: cobra.ExactArgs(0),
}

o.format.AddSingleValueFormattingFlags(cmd, common.FormatYAML)
return cmd
}

func (o *versionOptions) run() error {
var data = struct {
Client *version.Info
Server *versionc.VersionInfo
}{}

data.Client = version.GetInfo()
err := o.InitializeClients(o.global.URL, o.global.Timeout, o.global.Verbose)

if err == nil {
data.Server, err = o.VersionClient.Get()
}

o.format.FormatValue(os.Stdout, data)

if err != nil {
return fmt.Errorf("could not retrieve server version information: %s", err.Error())
}

return nil
}
Loading

0 comments on commit 689e963

Please sign in to comment.