Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions cmd/deploy/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,20 @@ func init() {
func execute(cmd *cobra.Command) {
env = config.EnsureEnvPresent(env)
ctx := cmd.Context()
traceID := util.GenerateTraceID()
contextWithTrace := context.WithValue(ctx, constant.TraceIDKey, traceID)
verboseEnabled, err := cmd.Flags().GetBool(constant.VerboseFlag)
if err != nil {
log.Fatal(err)
}

contextWithTrace = context.WithValue(contextWithTrace, constant.VerboseEnabledKey, verboseEnabled)

if isStrictEnvironment(contextWithTrace, env) {
if isStrictEnvironment(ctx, env) {
consentMessage := fmt.Sprintf(constant.ConsentMessageTemplate, env)
util.AskForConfirmation(env, consentMessage)
}

if (serviceName == "" && serviceVersion == "" && labels == "") && (definitionFile != "" && provisioningFile != "") {
deployUsingFiles(contextWithTrace)
deployUsingFiles(ctx)
} else if (serviceName != "" && serviceVersion != "" && labels == "") && (definitionFile == "" && provisioningFile == "") {
deployUsingServiceNameAndVersion(contextWithTrace)
deployUsingServiceNameAndVersion(ctx)
} else if (serviceName != "" && labels != "" && serviceVersion == "") && (definitionFile == "" && provisioningFile == "") {
if err := validateLabels(labels); err != nil {
log.Fatal("Invalid labels format: ", err)
}
deployUsingServiceNameAndLabels(contextWithTrace)
deployUsingServiceNameAndLabels(ctx)
} else {
log.Fatal("Invalid combination of flags. Use either (service name and version) or (definitionFile and provisioningFile).")
}
Expand Down
28 changes: 6 additions & 22 deletions internal/service/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"time"

"github.com/dream11/odin/pkg/config"
"github.com/dream11/odin/pkg/constant"
"github.com/dream11/odin/pkg/util"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
Expand All @@ -23,34 +21,20 @@ func getTLSOpts(appConfig *configuration.Configuration) grpc.DialOption {
tlsConf := tls.Config{
ServerName: strings.Split(appConfig.BackendAddress, ":")[0],
}
if appConfig.Plaintext {
// Disable TLS
return grpc.WithTransportCredentials(insecure.NewCredentials())
}
if appConfig.Insecure {
// Perform TLS handshake but skip certificate verification
tlsConf.InsecureSkipVerify = true
}
// Disable TLS
return grpc.WithTransportCredentials(insecure.NewCredentials())

return grpc.WithTransportCredentials(credentials.NewTLS(&tlsConf))

}

func grpcClient(ctx *context.Context) (*grpc.ClientConn, *context.Context, error) {
appConfig := config.GetConfig()
var traceID string
var contextWithTrace context.Context
if (*ctx).Value(constant.TraceIDKey) == nil {
traceID = util.GenerateTraceID()
contextWithTrace = context.WithValue(*ctx, constant.TraceIDKey, traceID)
} else {
traceID = (*ctx).Value(constant.TraceIDKey).(string)
contextWithTrace = *ctx
}

if appConfig.BackendAddress == "" {
log.Fatal("Cannot create grpc client: Backend address is empty in config! Run `odin configure` to set backend address")
}

opts := []grpc.DialOption{
grpc.WithKeepaliveParams(
keepalive.ClientParameters{
Expand All @@ -61,11 +45,11 @@ func grpcClient(ctx *context.Context) (*grpc.ClientConn, *context.Context, error
getTLSOpts(appConfig),
}
conn, err := grpc.NewClient(appConfig.BackendAddress, opts...)

if err != nil {
return nil, nil, err
}
// Enrich context with authorisation metadata
requestCtx := metadata.AppendToOutgoingContext(contextWithTrace, "Authorization", fmt.Sprintf("Bearer %s", appConfig.AccessToken), string(constant.TraceIDKey), traceID)

// Enrich context with authorization metadata only
requestCtx := metadata.AppendToOutgoingContext(*ctx, "Authorization", fmt.Sprintf("Bearer %s", appConfig.AccessToken))
return conn, &requestCtx, nil
}
7 changes: 5 additions & 2 deletions internal/service/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (e *Component) OperateComponent(ctx *context.Context, request *serviceProto
defer cancelFunction()

// Start log streaming in background
go streamLogs(streamCtx, ctx, request.GetServiceName())
go streamLogs(streamCtx, ctx, request.GetServiceName(), request.GetEnvName())

// Attempt operation with retries
return retry.Do(
Expand Down Expand Up @@ -52,8 +52,11 @@ func (e *Component) OperateComponent(ctx *context.Context, request *serviceProto
return response.GetServiceResponse().GetServiceStatus().GetServiceStatus(),
response.GetServiceResponse().GetServiceStatus().GetServiceAction()
}
getTraceId := func(response *serviceProto.OperateServiceResponse) string {
return response.GetTraceId()
}

return handleResponse(stream, cancelFunction, getMessage, getStatus)
return handleResponse(stream, cancelFunction, getMessage, getStatus, getTraceId)
},
retry.Delay(constant.Delay),
retry.RetryIf(isRetryableError),
Expand Down
13 changes: 13 additions & 0 deletions internal/service/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func (e *Environment) CreateEnvironment(ctx *context.Context, request *environme
return err
}
var message string
var traceID string
for {
response, err := stream.Recv()
spinnerInstance.Stop()
Expand All @@ -61,6 +62,12 @@ func (e *Environment) CreateEnvironment(ctx *context.Context, request *environme
return err
}
if response != nil {
// Print Trace ID only once, when it first arrives
if traceID == "" && response.TraceId != "" {
traceID = response.TraceId
log.Infof("Generated Trace Id for env creation: %s", traceID)
}

message = response.Message
spinnerInstance.Prefix = fmt.Sprintf(" %s ", response.Message)
spinnerInstance.Start()
Expand Down Expand Up @@ -91,6 +98,7 @@ func (e *Environment) DeleteEnvironment(ctx *context.Context, request *environme
return err
}
var message string
var traceID string
for {
response, err := stream.Recv()
spinnerInstance.Stop()
Expand All @@ -101,6 +109,11 @@ func (e *Environment) DeleteEnvironment(ctx *context.Context, request *environme
return err
}
if response != nil {
// Print Trace ID only once, when it first arrives
if traceID == "" && response.TraceId != "" {
traceID = response.TraceId
log.Infof("Generated Trace Id for env creation: %s", traceID)
}
message = response.Message
spinnerInstance.Prefix = fmt.Sprintf(" %s ", response.Message)
spinnerInstance.Start()
Expand Down
74 changes: 49 additions & 25 deletions internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type getStatus[R any] func(response R) (serviceAction, serviceStatus string)

type getMessage[R any] func(response R) string

type getTraceId[R any] func(response R) string

// DeployService deploys service
func (e *Service) DeployService(ctx *context.Context, request *serviceProto.DeployServiceRequest) error {
log.Info("Deploying Service...")
Expand All @@ -57,7 +59,7 @@ func (e *Service) DeployService(ctx *context.Context, request *serviceProto.Depl
defer cancelFunction()

// Start log streaming in background
go streamLogs(streamCtx, ctx, request.GetServiceDefinition().GetName())
go streamLogs(streamCtx, ctx, request.GetServiceDefinition().GetName(), request.GetEnvName())

// Attempt deployment with retries
return retry.Do(
Expand Down Expand Up @@ -86,7 +88,11 @@ func (e *Service) DeployService(ctx *context.Context, request *serviceProto.Depl
response.GetServiceResponse().GetServiceStatus().GetServiceAction()
}

return handleResponse(stream, cancelFunction, getMessage, getStatus)
getTraceId := func(response *serviceProto.DeployServiceResponse) string {
return response.GetTraceId()
}

return handleResponse(stream, cancelFunction, getMessage, getStatus, getTraceId)
},
retry.Delay(constant.Delay),
retry.RetryIf(isRetryableError),
Expand Down Expand Up @@ -162,7 +168,7 @@ func (e *Service) DeployReleasedService(ctx *context.Context, request *servicePr
defer cancelFunction()

// Start log streaming in background
go streamLogs(streamCtx, ctx, request.GetServiceIdentifier().GetServiceName())
go streamLogs(streamCtx, ctx, request.GetServiceIdentifier().GetServiceName(), request.GetEnvName())

// Attempt deployment with retries
return retry.Do(
Expand Down Expand Up @@ -192,7 +198,11 @@ func (e *Service) DeployReleasedService(ctx *context.Context, request *servicePr
response.GetServiceResponse().GetServiceStatus().GetServiceAction()
}

return handleResponse(stream, cancelFunction, getMessage, getStatus)
getTraceId := func(response *serviceProto.DeployReleasedServiceResponse) string {
return response.GetTraceId()
}

return handleResponse(stream, cancelFunction, getMessage, getStatus, getTraceId)
},
retry.Delay(constant.Delay),
retry.RetryIf(isRetryableError),
Expand All @@ -210,7 +220,7 @@ func (e *Service) UndeployService(ctx *context.Context, request *serviceProto.Un
defer cancelFunction()

// Start log streaming in background
go streamLogs(streamCtx, &contextWithTrace, request.GetServiceName())
go streamLogs(streamCtx, &contextWithTrace, request.GetServiceName(), request.GetEnvName())

conn, requestCtx, err := grpcClient(&contextWithTrace)
if err != nil {
Expand Down Expand Up @@ -261,7 +271,7 @@ func (e *Service) OperateService(ctx *context.Context, request *serviceProto.Ope
defer cancelFunction()

// Start log streaming in background
go streamLogs(streamCtx, ctx, request.GetServiceName())
go streamLogs(streamCtx, ctx, request.GetServiceName(), request.GetEnvName())

// Attempt operation with retries
return retry.Do(
Expand Down Expand Up @@ -290,7 +300,11 @@ func (e *Service) OperateService(ctx *context.Context, request *serviceProto.Ope
response.GetServiceResponse().GetServiceStatus().GetServiceAction()
}

return handleResponse(stream, cancelFunction, getMessage, getStatus)
getTraceId := func(response *serviceProto.OperateServiceResponse) string {
return response.GetTraceId()
}

return handleResponse(stream, cancelFunction, getMessage, getStatus, getTraceId)
},
retry.Delay(constant.Delay),
retry.RetryIf(isRetryableError),
Expand Down Expand Up @@ -403,37 +417,37 @@ func (e *Service) GetConflictingServices(ctx *context.Context, request *serviceP
}

// streamLogs streams logs for a service
func streamLogs(streamCtx context.Context, ctx *context.Context, serviceName string) {
func streamLogs(streamCtx context.Context, ctx *context.Context, serviceName string, envName string) {
var err error
lastLogTime := int64(0)
traceID := (*ctx).Value(constant.TraceIDKey).(string)
//traceID := (*ctx).Value(constant.TraceIDKey).(string)
follow := true
// Start the spinner in a background goroutine
go func() {
spinnerInstance := spinner.New(spinner.CharSets[constant.SpinnerType], constant.SpinnerDelay)
err = spinnerInstance.Color(constant.SpinnerColor, constant.SpinnerStyle)
if err != nil {
spinnerInstance.Stop()
}
spinnerInstance.Prefix = fmt.Sprintf("Fetching live logs for service: %s ", serviceName)
spinnerInstance.Suffix = "\n"
spinnerInstance.Start()
time.Sleep(30 * time.Second)
spinnerInstance.Stop()
fmt.Printf("Fetching live logs for service: %s \n", serviceName)
}()

//go func() {
//spinnerInstance := spinner.New(spinner.CharSets[constant.SpinnerType], constant.SpinnerDelay)
//err = spinnerInstance.Color(constant.SpinnerColor, constant.SpinnerStyle)
//if err != nil {
// spinnerInstance.Stop()
//}
//spinnerInstance.Prefix = fmt.Sprintf("Fetching live logs for service: %s ", serviceName)
//spinnerInstance.Suffix = "\n"
//spinnerInstance.Start()
//time.Sleep(30 * time.Second)
//spinnerInstance.Stop()

//}()
fmt.Printf("Fetching live logs for service: %s \n", serviceName)
for {
select {
case <-streamCtx.Done():
return
default:
// Get logs with retry on error
lastLogTime, err = logsClient.GetLogs(ctx, &logs.GetLogsRequest{
TraceId: &traceID,
Follow: &follow,
ServiceName: &serviceName,
StartTime: &lastLogTime,
EnvName: &envName,
})

if err != nil {
Expand All @@ -445,10 +459,20 @@ func streamLogs(streamCtx context.Context, ctx *context.Context, serviceName str
}

// handleResponse streams the service deploy response and call cancel on action termination
func handleResponse[S StreamReceiverInterface[R], R any](stream S, cancelFunc context.CancelFunc, getMessage getMessage[R], getStatus getStatus[R]) error {
func handleResponse[S StreamReceiverInterface[R], R any](stream S, cancelFunc context.CancelFunc, getMessage getMessage[R], getStatus getStatus[R], getTraceId getTraceId[R]) error {
var serviceAction, serviceStatus string
var traceID string
traceIdLogged := false
for {
response, err := stream.Recv()
traceID = getTraceId(response)
if !traceIdLogged {
if traceID != "" {
log.Info("Generated Trace Id for deploy service: ", traceID)
traceIdLogged = true
}
}

if err != nil {
if isActionCompleted(serviceAction, serviceStatus) {
cancelFunc()
Expand Down
7 changes: 7 additions & 0 deletions proto/dream11/od/environment/v1/environment.proto
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,25 @@ message CreateEnvironmentRequest {
string env_name = 1;
repeated string accounts = 2;
string provisioning_type = 3;
optional string trace_id = 4;

}

message CreateEnvironmentResponse {
string message = 1;
string trace_id = 2;

}

message DeleteEnvironmentRequest {
string env_name = 1;
optional string trace_id = 2;
}

message DeleteEnvironmentResponse {
string message = 1;
string trace_id = 2;

}

message IsStrictEnvironmentRequest {
Expand Down
4 changes: 2 additions & 2 deletions proto/dream11/od/logs/v1/logs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ service LogsService {
}

message GetLogsRequest {
string trace_id = 1;
optional bool follow = 2;
optional string service_name = 3;
optional string component_name = 4;
optional int64 start_time = 5;
optional string env_name = 5;
optional int64 start_time = 6;
}

message GetLogsResponse {
Expand Down
Loading