Skip to content

Commit

Permalink
Implement a central endpoint to select Overmind Instance
Browse files Browse the repository at this point in the history
The new `--app` commandline flag is a
one-stop-shop to set all instance-specific values
from data in the frontend. This allows for a more
consistent and less error-prone way to select the
instance to work with. Notably this requires the
user to specify a frontend URL, which is easily
copy-pasted from the browser.
  • Loading branch information
DavidS-ovm committed Feb 28, 2024
1 parent a6ed11b commit 59e8c03
Show file tree
Hide file tree
Showing 15 changed files with 285 additions and 133 deletions.
50 changes: 21 additions & 29 deletions cmd/auth_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,70 +8,62 @@ import (
"github.com/overmindtech/sdp-go"
"github.com/overmindtech/sdp-go/sdpconnect"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

// AuthenticatedApiKeyClient Returns an apikey client that uses the auth
// embedded in the context and otel instrumentation
func AuthenticatedApiKeyClient(ctx context.Context) sdpconnect.ApiKeyServiceClient {
func AuthenticatedApiKeyClient(ctx context.Context, oi OvermindInstance) sdpconnect.ApiKeyServiceClient {
httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient)
url := viper.GetString("url")
log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind apikeys API (pre-authenticated)")
return sdpconnect.NewApiKeyServiceClient(httpClient, url)
log.WithContext(ctx).WithField("apiUrl", oi.ApiUrl).Debug("Connecting to overmind apikeys API (pre-authenticated)")
return sdpconnect.NewApiKeyServiceClient(httpClient, oi.ApiUrl.String())
}

// UnauthenticatedApiKeyClient Returns an apikey client with otel instrumentation
// but no authentication. Can only be used for ExchangeKeyForToken
func UnauthenticatedApiKeyClient(ctx context.Context) sdpconnect.ApiKeyServiceClient {
url := viper.GetString("url")
log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind apikeys API")
return sdpconnect.NewApiKeyServiceClient(otelhttp.DefaultClient, url)
func UnauthenticatedApiKeyClient(ctx context.Context, oi OvermindInstance) sdpconnect.ApiKeyServiceClient {
log.WithContext(ctx).WithField("apiUrl", oi.ApiUrl).Debug("Connecting to overmind apikeys API")
return sdpconnect.NewApiKeyServiceClient(otelhttp.DefaultClient, oi.ApiUrl.String())
}

// AuthenticatedBookmarkClient Returns a bookmark client that uses the auth
// embedded in the context and otel instrumentation
func AuthenticatedBookmarkClient(ctx context.Context) sdpconnect.BookmarksServiceClient {
func AuthenticatedBookmarkClient(ctx context.Context, oi OvermindInstance) sdpconnect.BookmarksServiceClient {
httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient)
url := viper.GetString("url")
log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind bookmark API")
return sdpconnect.NewBookmarksServiceClient(httpClient, url)
log.WithContext(ctx).WithField("apiUrl", oi.ApiUrl).Debug("Connecting to overmind bookmark API")
return sdpconnect.NewBookmarksServiceClient(httpClient, oi.ApiUrl.String())
}

// AuthenticatedChangesClient Returns a bookmark client that uses the auth
// embedded in the context and otel instrumentation
func AuthenticatedChangesClient(ctx context.Context) sdpconnect.ChangesServiceClient {
func AuthenticatedChangesClient(ctx context.Context, oi OvermindInstance) sdpconnect.ChangesServiceClient {
httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient)
url := viper.GetString("url")
log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind changes API")
return sdpconnect.NewChangesServiceClient(httpClient, url)
log.WithContext(ctx).WithField("apiUrl", oi.ApiUrl).Debug("Connecting to overmind changes API")
return sdpconnect.NewChangesServiceClient(httpClient, oi.ApiUrl.String())
}

// AuthenticatedManagementClient Returns a bookmark client that uses the auth
// embedded in the context and otel instrumentation
func AuthenticatedManagementClient(ctx context.Context) sdpconnect.ManagementServiceClient {
func AuthenticatedManagementClient(ctx context.Context, oi OvermindInstance) sdpconnect.ManagementServiceClient {
httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient)
url := viper.GetString("url")
log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind management API")
return sdpconnect.NewManagementServiceClient(httpClient, url)
log.WithContext(ctx).WithField("apiUrl", oi.ApiUrl).Debug("Connecting to overmind management API")
return sdpconnect.NewManagementServiceClient(httpClient, oi.ApiUrl.String())
}

// AuthenticatedSnapshotsClient Returns a Snapshots client that uses the auth
// embedded in the context and otel instrumentation
func AuthenticatedSnapshotsClient(ctx context.Context) sdpconnect.SnapshotsServiceClient {
func AuthenticatedSnapshotsClient(ctx context.Context, oi OvermindInstance) sdpconnect.SnapshotsServiceClient {
httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient)
url := viper.GetString("url")
log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind snapshot API")
return sdpconnect.NewSnapshotsServiceClient(httpClient, url)
log.WithContext(ctx).WithField("apiUrl", oi.ApiUrl).Debug("Connecting to overmind snapshot API")
return sdpconnect.NewSnapshotsServiceClient(httpClient, oi.ApiUrl.String())
}

// AuthenticatedInviteClient Returns a Invite client that uses the auth
// embedded in the context and otel instrumentation
func AuthenticatedInviteClient(ctx context.Context) sdpconnect.InviteServiceClient {
func AuthenticatedInviteClient(ctx context.Context, oi OvermindInstance) sdpconnect.InviteServiceClient {
httpClient := NewAuthenticatedClient(ctx, otelhttp.DefaultClient)
url := viper.GetString("url")
log.WithContext(ctx).WithField("url", url).Debug("Connecting to overmind invite API")
return sdpconnect.NewInviteServiceClient(httpClient, url)
log.WithContext(ctx).WithField("apiUrl", oi.ApiUrl).Debug("Connecting to overmind invite API")
return sdpconnect.NewInviteServiceClient(httpClient, oi.ApiUrl.String())
}

// AuthenticatedClient is a http.Client that will automatically add the required
Expand Down
22 changes: 14 additions & 8 deletions cmd/bookmarks_create_bookmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,19 @@ func CreateBookmark(ctx context.Context, ready chan bool) int {
))
defer span.End()

ctx, err = ensureToken(ctx, []string{"changes:write"})
lf := log.Fields{
"app": viper.GetString("app"),
}

oi, err := NewOvermindInstance(ctx, viper.GetString("app"))
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get instance data from app")
return 1
}

ctx, err = ensureToken(ctx, oi, []string{"changes:write"})
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(log.Fields{
"url": viper.GetString("url"),
}).Error("failed to authenticate")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to authenticate")
return 1
}

Expand All @@ -100,16 +108,14 @@ func CreateBookmark(ctx context.Context, ready chan bool) int {
log.WithContext(ctx).WithError(err).Error("failed to parse input")
return 1
}
client := AuthenticatedBookmarkClient(ctx)
client := AuthenticatedBookmarkClient(ctx, oi)
response, err := client.CreateBookmark(ctx, &connect.Request[sdp.CreateBookmarkRequest]{
Msg: &sdp.CreateBookmarkRequest{
Properties: &msg,
},
})
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(log.Fields{
"url": viper.GetString("url"),
}).Error("failed to get bookmark")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get bookmark")
return 1
}
log.WithContext(ctx).WithFields(log.Fields{
Expand Down
22 changes: 14 additions & 8 deletions cmd/bookmarks_get_affected_bookmarks.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,29 +81,35 @@ func GetAffectedBookmarks(ctx context.Context, ready chan bool) int {
))
defer span.End()

ctx, err = ensureToken(ctx, []string{"changes:read"})
lf := log.Fields{
"app": viper.GetString("app"),
}

oi, err := NewOvermindInstance(ctx, viper.GetString("app"))
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get instance data from app")
return 1
}

ctx, err = ensureToken(ctx, oi, []string{"changes:read"})
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(log.Fields{
"url": viper.GetString("url"),
}).Error("failed to authenticate")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to authenticate")
return 1
}

// apply a timeout to the main body of processing
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

client := AuthenticatedBookmarkClient(ctx)
client := AuthenticatedBookmarkClient(ctx, oi)
response, err := client.GetAffectedBookmarks(ctx, &connect.Request[sdp.GetAffectedBookmarksRequest]{
Msg: &sdp.GetAffectedBookmarksRequest{
SnapshotUUID: snapshotUuid[:],
BookmarkUUIDs: bookmarkUuids,
},
})
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(log.Fields{
"url": viper.GetString("url"),
}).Error("failed to get affected bookmarks")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get affected bookmarks")
return 1
}
for _, u := range response.Msg.GetBookmarkUUIDs() {
Expand Down
22 changes: 14 additions & 8 deletions cmd/bookmarks_get_bookmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,34 @@ func GetBookmark(ctx context.Context, ready chan bool) int {
))
defer span.End()

ctx, err = ensureToken(ctx, []string{"changes:read"})
lf := log.Fields{
"app": viper.GetString("app"),
}

oi, err := NewOvermindInstance(ctx, viper.GetString("app"))
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get instance data from app")
return 1
}

ctx, err = ensureToken(ctx, oi, []string{"changes:read"})
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(log.Fields{
"url": viper.GetString("url"),
}).Error("failed to authenticate")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to authenticate")
return 1
}

// apply a timeout to the main body of processing
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

client := AuthenticatedBookmarkClient(ctx)
client := AuthenticatedBookmarkClient(ctx, oi)
response, err := client.GetBookmark(ctx, &connect.Request[sdp.GetBookmarkRequest]{
Msg: &sdp.GetBookmarkRequest{
UUID: bookmarkUuid[:],
},
})
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(log.Fields{
"url": viper.GetString("url"),
}).Error("failed to get bookmark")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get bookmark")
return 1
}
log.WithContext(ctx).WithFields(log.Fields{
Expand Down
21 changes: 14 additions & 7 deletions cmd/changes_end_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,27 @@ func EndChange(ctx context.Context, ready chan bool) int {
))
defer span.End()

ctx, err = ensureToken(ctx, []string{"changes:write"})
lf := log.Fields{
"app": viper.GetString("app"),
}

oi, err := NewOvermindInstance(ctx, viper.GetString("app"))
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get instance data from app")
return 1
}

ctx, err = ensureToken(ctx, oi, []string{"changes:write"})
if err != nil {
log.WithContext(ctx).WithFields(log.Fields{
"url": viper.GetString("url"),
}).WithError(err).Error("failed to authenticate")
log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate")
return 1
}

// apply a timeout to the main body of processing
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

lf := log.Fields{}
changeUuid, err := getChangeUuid(ctx, sdp.ChangeStatus_CHANGE_STATUS_HAPPENING, true)
changeUuid, err := getChangeUuid(ctx, oi, sdp.ChangeStatus_CHANGE_STATUS_HAPPENING, true)
if err != nil {
log.WithError(err).WithFields(lf).Error("failed to identify change")
return 1
Expand All @@ -85,7 +92,7 @@ func EndChange(ctx context.Context, ready chan bool) int {
lf["uuid"] = changeUuid.String()

// snapClient := AuthenticatedSnapshotsClient(ctx)
client := AuthenticatedChangesClient(ctx)
client := AuthenticatedChangesClient(ctx, oi)
stream, err := client.EndChange(ctx, &connect.Request[sdp.EndChangeRequest]{
Msg: &sdp.EndChangeRequest{
ChangeUUID: changeUuid[:],
Expand Down
21 changes: 14 additions & 7 deletions cmd/changes_get_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,35 @@ func GetChange(ctx context.Context, ready chan bool) int {
))
defer span.End()

ctx, err = ensureToken(ctx, []string{"changes:read"})
lf := log.Fields{
"app": viper.GetString("app"),
}

oi, err := NewOvermindInstance(ctx, viper.GetString("app"))
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get instance data from app")
return 1
}

ctx, err = ensureToken(ctx, oi, []string{"changes:read"})
if err != nil {
log.WithContext(ctx).WithFields(log.Fields{
"url": viper.GetString("url"),
}).WithError(err).Error("failed to authenticate")
log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate")
return 1
}

// apply a timeout to the main body of processing
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

lf := log.Fields{}
changeUuid, err := getChangeUuid(ctx, sdp.ChangeStatus(sdp.ChangeStatus_value[viper.GetString("status")]), true)
changeUuid, err := getChangeUuid(ctx, oi, sdp.ChangeStatus(sdp.ChangeStatus_value[viper.GetString("status")]), true)
if err != nil {
log.WithError(err).WithFields(lf).Error("failed to identify change")
return 1
}

lf["uuid"] = changeUuid.String()

client := AuthenticatedChangesClient(ctx)
client := AuthenticatedChangesClient(ctx, oi)
var riskRes *connect.Response[sdp.GetChangeRisksResponse]
fetch:
for {
Expand Down
24 changes: 16 additions & 8 deletions cmd/changes_list_changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,27 +66,35 @@ func ListChanges(ctx context.Context, ready chan bool) int {
))
defer span.End()

ctx, err = ensureToken(ctx, []string{"changes:read"})
lf := log.Fields{
"app": viper.GetString("app"),
}

oi, err := NewOvermindInstance(ctx, viper.GetString("app"))
if err != nil {
log.WithContext(ctx).WithFields(log.Fields{
"url": viper.GetString("url"),
}).WithError(err).Error("failed to authenticate")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get instance data from app")
return 1
}

ctx, err = ensureToken(ctx, oi, []string{"changes:read"})
if err != nil {
log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate")
return 1
}

// apply a timeout to the main body of processing
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

snapshots := AuthenticatedSnapshotsClient(ctx)
bookmarks := AuthenticatedBookmarkClient(ctx)
changes := AuthenticatedChangesClient(ctx)
snapshots := AuthenticatedSnapshotsClient(ctx, oi)
bookmarks := AuthenticatedBookmarkClient(ctx, oi)
changes := AuthenticatedChangesClient(ctx, oi)

response, err := changes.ListChanges(ctx, &connect.Request[sdp.ListChangesRequest]{
Msg: &sdp.ListChangesRequest{},
})
if err != nil {
log.WithContext(ctx).WithError(err).Error("failed to list changes")
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to list changes")
return 1
}
for _, change := range response.Msg.GetChanges() {
Expand Down
19 changes: 13 additions & 6 deletions cmd/changes_manual_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"connectrpc.com/connect"
"github.com/google/uuid"
"github.com/overmindtech/cli/internal"
"github.com/overmindtech/cli/tracing"
"github.com/overmindtech/sdp-go"
"github.com/overmindtech/sdp-go/sdpws"
Expand Down Expand Up @@ -68,9 +67,17 @@ func ManualChange(ctx context.Context, ready chan bool) int {
))
defer span.End()

lf := log.Fields{}
lf := log.Fields{
"app": viper.GetString("app"),
}

oi, err := NewOvermindInstance(ctx, viper.GetString("app"))
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to get instance data from app")
return 1
}

ctx, err = ensureToken(ctx, []string{"changes:write"})
ctx, err = ensureToken(ctx, oi, []string{"changes:write"})
if err != nil {
log.WithContext(ctx).WithFields(lf).WithError(err).Error("failed to authenticate")
return 1
Expand All @@ -80,8 +87,8 @@ func ManualChange(ctx context.Context, ready chan bool) int {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

client := AuthenticatedChangesClient(ctx)
changeUuid, err := getChangeUuid(ctx, sdp.ChangeStatus_CHANGE_STATUS_DEFINING, false)
client := AuthenticatedChangesClient(ctx, oi)
changeUuid, err := getChangeUuid(ctx, oi, sdp.ChangeStatus_CHANGE_STATUS_DEFINING, false)
if err != nil {
log.WithContext(ctx).WithError(err).WithFields(lf).Error("failed to searching for existing changes")
return 1
Expand Down Expand Up @@ -125,7 +132,7 @@ func ManualChange(ctx context.Context, ready chan bool) int {
return 1
}

ws, err := sdpws.DialBatch(ctx, internal.GatewayURL(viper.GetString("url")), otelhttp.DefaultClient, nil)
ws, err := sdpws.DialBatch(ctx, oi.GatewayUrl(), otelhttp.DefaultClient, nil)
if err != nil {
log.WithContext(ctx).WithFields(lf).WithError(err).Error("Failed to connect to gateway")
return 1
Expand Down
Loading

0 comments on commit 59e8c03

Please sign in to comment.