Skip to content

Commit

Permalink
feat: Added levels of connectivity to connect command
Browse files Browse the repository at this point in the history
* Card ID: CCT-1005
* First step of levels of connectivity
* When connect command is used, then it is possible to
  enabled or disable three features using command line
  options --enable-feature or --disable-feature. Following
  features are supported
  - content
  - analytics
  - remote-management
* Added checks for allowed combination of CLI options
* Modified UI little bit to be able to visualize that
  feature was not started
* Output to JSON format is still supported, but it was
  modified.
* When machine readable format is used, then information
  about features could be following:

{
    "hostname": "localhost",
    "uid": 0,
    "rhsm_connected": true,
    "features": {
        "content": {
            "enabled": true,
            "successful": true
        },
        "analytics": {
            "enabled": true,
            "successful": false,
            "error": "some error message"
        },
        "remote_management": {
            "enabled": false,
            "successful": false
        }
    }
}
  • Loading branch information
jirihnidek committed Jan 7, 2025
1 parent 0345b25 commit bd93706
Show file tree
Hide file tree
Showing 7 changed files with 395 additions and 97 deletions.
234 changes: 171 additions & 63 deletions connect_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,35 @@ package main
import (
"encoding/json"
"fmt"
"github.com/subpop/go-log"
"github.com/urfave/cli/v2"
"os"
"strings"
"time"

"github.com/subpop/go-log"
"github.com/urfave/cli/v2"
)

type FeatureResult struct {
Enabled bool `json:"enabled"`
Successful bool `json:"successful"`
Error string `json:"error,omitempty"`
}

// ConnectResult is structure holding information about results
// of connect command. The result could be printed in machine-readable format.
type ConnectResult struct {
Hostname string `json:"hostname"`
HostnameError string `json:"hostname_error,omitempty"`
UID int `json:"uid"`
UIDError string `json:"uid_error,omitempty"`
RHSMConnected bool `json:"rhsm_connected"`
RHSMConnectError string `json:"rhsm_connect_error,omitempty"`
InsightsConnected bool `json:"insights_connected"`
InsightsError string `json:"insights_connect_error,omitempty"`
YggdrasilStarted bool `json:"yggdrasil_started"`
YggdrasilStartedError string `json:"yggdrasil_started_error,omitempty"`
format string
Hostname string `json:"hostname"`
HostnameError string `json:"hostname_error,omitempty"`
UID int `json:"uid"`
UIDError string `json:"uid_error,omitempty"`
RHSMConnected bool `json:"rhsm_connected"`
RHSMConnectError string `json:"rhsm_connect_error,omitempty"`
Features struct {
Content FeatureResult `json:"content"`
Analytics FeatureResult `json:"analytics"`
RemoteManagement FeatureResult `json:"remote_management"`
} `json:"features"`
format string
}

// Error implement error interface for structure ConnectResult
Expand Down Expand Up @@ -56,6 +65,8 @@ func beforeConnectAction(ctx *cli.Context) error {
password := ctx.String("password")
organization := ctx.String("organization")
activationKeys := ctx.StringSlice("activation-key")
enabledFeatures := ctx.StringSlice("enable-feature")
disabledFeatures := ctx.StringSlice("disable-feature")

if len(activationKeys) > 0 {
if username != "" {
Expand All @@ -73,6 +84,11 @@ func beforeConnectAction(ctx *cli.Context) error {
}
}

err = checkFeatureInput(&enabledFeatures, &disabledFeatures)
if err != nil {
return err
}

return checkForUnknownArgs(ctx)
}

Expand Down Expand Up @@ -112,13 +128,44 @@ func connectAction(ctx *cli.Context) error {

interactivePrintf("Connecting %v to %v.\nThis might take a few seconds.\n\n", hostname, Provider)

var featuresStr []string
for _, feature := range KnownFeatures {
if feature.Enabled {
if uiSettings.isMachineReadable {
switch feature.ID {
case "content":
connectResult.Features.Content.Enabled = true
case "analytics":
connectResult.Features.Analytics.Enabled = true
case "remote-management":
connectResult.Features.RemoteManagement.Enabled = true
}
}
featuresStr = append(featuresStr, "["+symbolOK+"]"+feature.ID)
} else {
if uiSettings.isMachineReadable {
switch feature.ID {
case "content":
connectResult.Features.Content.Enabled = false
case "analytics":
connectResult.Features.Analytics.Enabled = false
case "remote-management":
connectResult.Features.RemoteManagement.Enabled = false
}
}
featuresStr = append(featuresStr, "[ ]"+feature.ID)
}
}
featuresListStr := strings.Join(featuresStr, ", ")
interactivePrintf("Features preferences: %s\n\n", featuresListStr)

var start time.Time
durations := make(map[string]time.Duration)
errorMessages := make(map[string]LogMessage)
/* 1. Register to RHSM, because we need to get consumer certificate. This blocks following action */
start = time.Now()
var returnedMsg string
returnedMsg, err = registerRHSM(ctx)
returnedMsg, err = registerRHSM(ctx, ContentFeature.Enabled)
if err != nil {
connectResult.RHSMConnected = false
errorMessages["rhsm"] = LogMessage{
Expand All @@ -127,77 +174,138 @@ func connectAction(ctx *cli.Context) error {
err)}
if uiSettings.isMachineReadable {
connectResult.RHSMConnectError = errorMessages["rhsm"].message.Error()
connectResult.Features.Content.Successful = false
} else {
fmt.Printf(
"%v Cannot connect to Red Hat Subscription Management\n",
"%s[%v] Cannot connect to Red Hat Subscription Management\n",
smallIndent,
uiSettings.iconError,
)
fmt.Printf(
"%s[%v] Skipping generation of Red Hat repository file\n",
mediumIndent,
uiSettings.iconError,
)
}
} else {
connectResult.RHSMConnected = true
interactivePrintf("%v %v\n", uiSettings.iconOK, returnedMsg)
interactivePrintf("%s[%v] %v\n", smallIndent, uiSettings.iconOK, returnedMsg)
if ContentFeature.Enabled {
if uiSettings.isMachineReadable {
connectResult.Features.Content.Successful = true
}
interactivePrintf(
"%s[%v] Content ... Red Hat repository file generated\n",
mediumIndent,
uiSettings.iconOK,
)
} else {
if uiSettings.isMachineReadable {
connectResult.Features.Content.Successful = false
}
interactivePrintf("%s[ ] Content ... Red Hat repository file not generated\n", mediumIndent)
}
}
durations["rhsm"] = time.Since(start)

/* 2. Register insights-client */
if errors, exist := errorMessages["rhsm"]; exist {
if errors.level == log.LevelError {
if AnalyticsFeature.Enabled {
if errors, exist := errorMessages["rhsm"]; exist {
if errors.level == log.LevelError {
interactivePrintf(
"%s[%v] Skipping connection to Red Hat Insights\n",
mediumIndent,
uiSettings.iconError,
)
}
} else {
start = time.Now()
err = showProgress(" Connecting to Red Hat Insights...", registerInsights, mediumIndent)
if err != nil {
connectResult.Features.Analytics.Successful = false
errorMessages["insights"] = LogMessage{
level: log.LevelError,
message: fmt.Errorf("cannot connect to Red Hat Insights: %w", err)}
if uiSettings.isMachineReadable {
connectResult.Features.Analytics.Error = errorMessages["insights"].message.Error()
} else {
fmt.Printf(
"%s[%v] Analytics ... Cannot connect to Red Hat Insights\n",
mediumIndent,
uiSettings.iconError,
)
}
} else {
connectResult.Features.Analytics.Successful = true
interactivePrintf(
"%s[%v] Analytics ... Connected to Red Hat Insights\n",
mediumIndent,
uiSettings.iconOK,
)
}
durations["insights"] = time.Since(start)
}
} else {
if uiSettings.isMachineReadable {
connectResult.Features.Analytics.Successful = false
}
interactivePrintf("%s[ ] Analytics ... Connecting to Red Hat Insights disabled\n", mediumIndent)
}

if ManagementFeature.Enabled {
/* 3. Start yggdrasil (rhcd) service */
if rhsmErrMsg, exist := errorMessages["rhsm"]; exist && rhsmErrMsg.level == log.LevelError {
connectResult.Features.RemoteManagement.Successful = false
interactivePrintf(
"%v Skipping connection to Red Hat Insights\n",
"%s[%v] Skipping activation of %v service\n",
mediumIndent,
uiSettings.iconError,
ServiceName,
)
}
} else {
start = time.Now()
err = showProgress(" Connecting to Red Hat Insights...", registerInsights)
if err != nil {
connectResult.InsightsConnected = false
errorMessages["insights"] = LogMessage{
level: log.LevelError,
message: fmt.Errorf("cannot connect to Red Hat Insights: %w", err)}
if uiSettings.isMachineReadable {
connectResult.InsightsError = errorMessages["insights"].message.Error()
} else {
start = time.Now()
progressMessage := fmt.Sprintf(" Activating the %v service", ServiceName)
err = showProgress(progressMessage, activateService, mediumIndent)
if err != nil {
connectResult.Features.RemoteManagement.Successful = false
errorMessages[ServiceName] = LogMessage{
level: log.LevelError,
message: fmt.Errorf("cannot activate %s service: %w",
ServiceName, err)}
if uiSettings.isMachineReadable {
connectResult.Features.RemoteManagement.Error = errorMessages[ServiceName].message.Error()
} else {
interactivePrintf(
"%s[%v] Remote Management ... Cannot activate the %v service\n",
mediumIndent,
uiSettings.iconError,
ServiceName,
)
}
} else {
fmt.Printf("%v Cannot connect to Red Hat Insights\n", uiSettings.iconError)
connectResult.Features.RemoteManagement.Successful = true
interactivePrintf(
"%s[%v] Remote Management ... Activated the %v service\n",
mediumIndent,
uiSettings.iconOK,
ServiceName,
)
}
} else {
connectResult.InsightsConnected = true
interactivePrintf("%v Connected to Red Hat Insights\n", uiSettings.iconOK)
durations[ServiceName] = time.Since(start)
}
} else {
if uiSettings.isMachineReadable {
connectResult.Features.RemoteManagement.Successful = false
}
durations["insights"] = time.Since(start)
}

/* 3. Start yggdrasil (rhcd) service */
if rhsmErrMsg, exist := errorMessages["rhsm"]; exist && rhsmErrMsg.level == log.LevelError {
connectResult.YggdrasilStarted = false
interactivePrintf(
"%v Skipping activation of %v service\n",
uiSettings.iconError,
"%s[ ] Management .... Starting %s service disabled\n",
mediumIndent,
ServiceName,
)
} else {
start = time.Now()
progressMessage := fmt.Sprintf(" Activating the %v service", ServiceName)
err = showProgress(progressMessage, activateService)
if err != nil {
connectResult.YggdrasilStarted = false
errorMessages[ServiceName] = LogMessage{
level: log.LevelError,
message: fmt.Errorf("cannot activate %s service: %w",
ServiceName, err)}
if uiSettings.isMachineReadable {
connectResult.YggdrasilStartedError = errorMessages[ServiceName].message.Error()
} else {
fmt.Printf("%v Cannot activate the %v service\n", uiSettings.iconError, ServiceName)
}
} else {
connectResult.YggdrasilStarted = true
interactivePrintf("%v Activated the %v service\n", uiSettings.iconOK, ServiceName)
}
durations[ServiceName] = time.Since(start)
interactivePrintf("\nSuccessfully connected to Red Hat!\n")
}

interactivePrintf("\nSuccessfully connected to Red Hat!\n")

if !uiSettings.isMachineReadable {
/* 5. Show footer message */
fmt.Printf("\nManage your connected systems: https://red.ht/connector\n")
Expand Down
3 changes: 3 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ func init() {
ServiceName = "yggdrasil"
}
}

const smallIndent = " "
const mediumIndent = " "
25 changes: 14 additions & 11 deletions disconnect_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package main
import (
"encoding/json"
"fmt"
"github.com/subpop/go-log"
"github.com/urfave/cli/v2"
"os"
"time"

"github.com/subpop/go-log"
"github.com/urfave/cli/v2"
)

// DisconnectResult is structure holding information about result of
Expand Down Expand Up @@ -95,41 +96,43 @@ func disconnectAction(ctx *cli.Context) error {
/* 1. Deactivate yggdrasil (rhcd) service */
start = time.Now()
progressMessage := fmt.Sprintf(" Deactivating the %v service", ServiceName)
err = showProgress(progressMessage, deactivateService)
err = showProgress(progressMessage, deactivateService, smallIndent)
if err != nil {
errMsg := fmt.Sprintf("Cannot deactivate %s service: %v", ServiceName, err)
errorMessages[ServiceName] = LogMessage{
level: log.LevelError,
message: fmt.Errorf("%v", errMsg)}
disconnectResult.YggdrasilStopped = false
disconnectResult.YggdrasilStoppedError = errMsg
interactivePrintf("%v %v\n", uiSettings.iconError, errMsg)
interactivePrintf(" [%v] %v\n", uiSettings.iconError, errMsg)
} else {
disconnectResult.YggdrasilStopped = true
interactivePrintf("%v Deactivated the %v service\n", uiSettings.iconOK, ServiceName)
interactivePrintf(" [%v] Deactivated the %v service\n", uiSettings.iconOK, ServiceName)
}
durations[ServiceName] = time.Since(start)

/* 2. Disconnect from Red Hat Insights */
start = time.Now()
err = showProgress(" Disconnecting from Red Hat Insights...", unregisterInsights)
err = showProgress(" Disconnecting from Red Hat Insights...", unregisterInsights, smallIndent)
if err != nil {
errMsg := fmt.Sprintf("Cannot disconnect from Red Hat Insights: %v", err)
errorMessages["insights"] = LogMessage{
level: log.LevelError,
message: fmt.Errorf("%v", errMsg)}
disconnectResult.InsightsDisconnected = false
disconnectResult.InsightsDisconnectedError = errMsg
interactivePrintf("%v %v\n", uiSettings.iconError, errMsg)
interactivePrintf(" [%v] %v\n", uiSettings.iconError, errMsg)
} else {
disconnectResult.InsightsDisconnected = true
interactivePrintf("%v Disconnected from Red Hat Insights\n", uiSettings.iconOK)
interactivePrintf(" [%v] Disconnected from Red Hat Insights\n", uiSettings.iconOK)
}
durations["insights"] = time.Since(start)

/* 3. Unregister system from Red Hat Subscription Management */
err = showProgress(
" Disconnecting from Red Hat Subscription Management...", unregister,
" Disconnecting from Red Hat Subscription Management...",
unregister,
smallIndent,
)
if err != nil {
errMsg := fmt.Sprintf("Cannot disconnect from Red Hat Subscription Management: %v", err)
Expand All @@ -139,10 +142,10 @@ func disconnectAction(ctx *cli.Context) error {

disconnectResult.RHSMDisconnected = false
disconnectResult.RHSMDisconnectedError = errMsg
interactivePrintf("%v %v\n", uiSettings.iconError, errMsg)
interactivePrintf(" [%v] %v\n", uiSettings.iconError, errMsg)
} else {
disconnectResult.RHSMDisconnected = true
interactivePrintf("%v Disconnected from Red Hat Subscription Management\n", uiSettings.iconOK)
interactivePrintf(" [%v] Disconnected from Red Hat Subscription Management\n", uiSettings.iconOK)
}
durations["rhsm"] = time.Since(start)

Expand Down
Loading

0 comments on commit bd93706

Please sign in to comment.