Skip to content

Commit 1d2b748

Browse files
authored
Various changes (#18)
* Add support for AWS session token * Change operator spec version * use latest * Disable telemetry * Really disable * Strip out telemetry * fix aws kube credential issues * Add better support for multiple users leveraging the bootstrapper at once * Proper state persistence * Use database config in deployemnts * Adds support for adding MattermostEnv variables via edit installation modal * Revert "feat: Add embedded frontend support with Go embed (#16)" This reverts commit 25cae4f. * Fix 400
1 parent 2c53526 commit 1d2b748

38 files changed

Lines changed: 665 additions & 477 deletions

.github/workflows/ci.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ defaults:
1111

1212
env:
1313
TERM: xterm
14+
GO_VERSION: 1.22.0
1415

1516
concurrency:
1617
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -28,7 +29,7 @@ jobs:
2829
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
2930
with:
3031
cache: true
31-
go-version-file: 'go.mod'
32+
go-version: ${{ env.GO_VERSION }}
3233
- name: ci/setup-node
3334
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
3435
with:

Makefile

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ build_desktop_desktop: build_desktop_macos
2222

2323
.PHONY: lint-server
2424
lint-server:
25-
@echo Running staticcheck
25+
@echo Running lint
2626
@echo $(GOBIN)
27-
GOBIN=$(GOBIN) $(GO) install honnef.co/go/tools/cmd/staticcheck@latest
28-
$(GOBIN)/staticcheck ./...
27+
GOBIN=$(GOBIN) $(GO) install golang.org/x/lint/golint
28+
$(GOBIN)/golint -set_exit_status $(./...)
2929
@echo lint success
3030

3131
.PHONY: govet
@@ -47,20 +47,4 @@ lint-webapp: node_modules
4747
cd webapp; npm run lint
4848

4949
.PHONY: check-style
50-
check-style: lint-server govet lint-webapp
51-
52-
.PHONY: build-webapp
53-
build-webapp: node_modules
54-
@echo Building webapp for production
55-
cd webapp; npm run build
56-
57-
.PHONY: build-server-embedded
58-
build-server-embedded: build-webapp
59-
@echo Building server with embedded frontend
60-
@echo Copying webapp build files to static/build
61-
rm -rf static/build
62-
mkdir -p static
63-
cp -r webapp/build static/
64-
go build -o build/mcnb-server ./cmd/mcnb
65-
@echo Cleaning up copied files
66-
rm -rf static/build
50+
check-style: lint-server govet lint-webapp

api/api.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@ func Register(rootRouter *mux.Router, c *Context) {
88
apiRouter := rootRouter.PathPrefix("/api/v1").Subrouter()
99
initBootstrapper(apiRouter, c)
1010
initState(apiRouter, c)
11-
initTelemetry(apiRouter, c)
1211
}

api/bootstrapper.go

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ func initBootstrapper(apiRouter *mux.Router, context *Context) {
7777
}
7878

7979
func handleSetCredentials(c *Context, w http.ResponseWriter, r *http.Request) {
80+
vars := mux.Vars(r)
81+
cloudProvider := vars["cloudProvider"]
82+
8083
var credentials model.Credentials
8184
json.NewDecoder(r.Body).Decode(&credentials)
8285

@@ -99,7 +102,8 @@ func handleSetCredentials(c *Context, w http.ResponseWriter, r *http.Request) {
99102
return
100103
}
101104

102-
err = UpdateStateCredentials(c.BootstrapperState, &credentials)
105+
// Update both credentials and provider in state
106+
err = UpdateStateCredentialsAndProvider(c.BootstrapperState, &credentials, cloudProvider)
103107
if err != nil {
104108
logger.FromContext(c.Ctx).WithError(err).Error("Failed to update state credentials - settings will not be persisted")
105109
}
@@ -199,6 +203,12 @@ func handleGetCluster(c *Context, w http.ResponseWriter, r *http.Request) {
199203
w.WriteHeader(http.StatusInternalServerError)
200204
}
201205

206+
// Update cluster name in state when accessing a cluster
207+
err = UpdateStateClusterName(c.BootstrapperState, clusterName)
208+
if err != nil {
209+
logger.FromContext(c.Ctx).WithError(err).Error("Failed to update cluster name in state")
210+
}
211+
202212
json.NewEncoder(w).Encode(result)
203213
}
204214

@@ -431,7 +441,7 @@ func handleDeployNginxOperator(c *Context, w http.ResponseWriter, r *http.Reques
431441
annotations:
432442
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
433443
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
434-
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:926412419614:certificate/e13f9426-e452-4670-9f6a-f56b3f346bf1`
444+
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:110643744285:certificate/8fcc5250-8a60-4ab8-8337-7491fb447906`
435445

436446
chartSpec := helmclient.ChartSpec{
437447
ReleaseName: "ingress-nginx",
@@ -754,6 +764,7 @@ func handlePatchMattermostInstallation(c *Context, w http.ResponseWriter, r *htt
754764
logger.FromContext(c.Ctx).Infof("Patch request: %+v", patchRequest.FilestorePatch)
755765

756766
if !patchRequest.IsValid() {
767+
logger.FromContext(c.Ctx).Errorf("Invalid patch request - version validation failed for version: %s", patchRequest.Version)
757768
w.WriteHeader(http.StatusBadRequest)
758769
return
759770
}
@@ -899,6 +910,12 @@ func handlePatchMattermostInstallation(c *Context, w http.ResponseWriter, r *htt
899910
database.External.Secret = updatedSecret.ObjectMeta.Name
900911
}
901912

913+
// Update environment variables if provided
914+
if len(patchRequest.MattermostEnv) > 0 {
915+
logger.FromContext(c.Ctx).Infof("Updating environment variables, count: %d", len(patchRequest.MattermostEnv))
916+
installation.Spec.MattermostEnv = patchRequest.MattermostEnv
917+
}
918+
902919
installation.Spec.Version = patchRequest.Version
903920
installation.Spec.Image = patchRequest.Image
904921
installation.Spec.FileStore = MMFilestore
@@ -1009,6 +1026,7 @@ func handleCreateMattermostInstallation(c *Context, w http.ResponseWriter, r *ht
10091026

10101027
var writer string
10111028
var reader string
1029+
var databaseSecretName string
10121030

10131031
if create.DBConnectionOption == model.DatabaseOptionCreateForMe {
10141032
dbCluster := &cnpgv1.Cluster{
@@ -1066,29 +1084,38 @@ func handleCreateMattermostInstallation(c *Context, w http.ResponseWriter, r *ht
10661084
writer = strings.Replace(initial, "postgresql:", "postgres:", 1) // Replace once
10671085
reader = strings.Replace(writer, fmt.Sprintf("%s-rw:", secretName), fmt.Sprintf("%s-ro:", secretName), 1)
10681086
} else if create.DBConnectionOption == model.DatabaseOptionExisting {
1069-
writer = create.ExistingDBConnection.ConnectionString
1070-
reader = create.ExistingDBConnection.ConnectionString
1087+
if create.ExistingDBSecretName != "" {
1088+
databaseSecretName = create.ExistingDBSecretName
1089+
} else {
1090+
writer = create.ExistingDBConnection.ConnectionString
1091+
reader = create.ExistingDBConnection.ConnectionString
1092+
}
10711093
}
10721094

1073-
databaseSecret := &v1.Secret{
1074-
ObjectMeta: metav1.ObjectMeta{
1075-
Name: model.SecretNameDatabase,
1076-
Namespace: namespaceName,
1077-
},
1078-
Type: v1.SecretTypeOpaque,
1079-
StringData: map[string]string{
1080-
"DB_CONNECTION_CHECK_URL": writer,
1081-
"DB_CONNECTION_STRING": writer,
1082-
"MM_SQLSETTINGS_DATASOURCEREPLICAS": reader, // Assuming read replicas for now
1083-
},
1084-
}
1095+
if databaseSecretName == "" {
1096+
databaseSecret := &v1.Secret{
1097+
ObjectMeta: metav1.ObjectMeta{
1098+
Name: model.SecretNameDatabase,
1099+
Namespace: namespaceName,
1100+
},
1101+
Type: v1.SecretTypeOpaque,
1102+
StringData: map[string]string{
1103+
"DB_CONNECTION_CHECK_URL": writer,
1104+
"DB_CONNECTION_STRING": writer,
1105+
"MM_SQLSETTINGS_DATASOURCEREPLICAS": reader, // Assuming read replicas for now
1106+
"MM_CONFIG": writer,
1107+
},
1108+
}
10851109

1086-
// Create the database secret
1087-
_, err = kubeClient.Clientset.CoreV1().Secrets(namespaceName).Create(context.TODO(), databaseSecret, metav1.CreateOptions{})
1088-
if err != nil {
1089-
logger.FromContext(c.Ctx).Errorf("Error creating database secret:", err)
1090-
w.WriteHeader(http.StatusInternalServerError)
1091-
return
1110+
// Create the database secret
1111+
_, err = kubeClient.Clientset.CoreV1().Secrets(namespaceName).Create(context.TODO(), databaseSecret, metav1.CreateOptions{})
1112+
if err != nil {
1113+
logger.FromContext(c.Ctx).Errorf("Error creating database secret:", err)
1114+
w.WriteHeader(http.StatusInternalServerError)
1115+
return
1116+
}
1117+
1118+
databaseSecretName = databaseSecret.ObjectMeta.Name
10921119
}
10931120

10941121
// License Secret
@@ -1114,6 +1141,9 @@ func handleCreateMattermostInstallation(c *Context, w http.ResponseWriter, r *ht
11141141
}
11151142

11161143
filestore := create.GetMMOperatorFilestore(namespaceName, filestoreSecret)
1144+
if filestore.External != nil && filestore.External.Secret == "" && create.FilestoreSecretName != "" {
1145+
filestore.External.Secret = create.FilestoreSecretName
1146+
}
11171147

11181148
mattermostCRD := &mmv1beta1.Mattermost{
11191149
ObjectMeta: metav1.ObjectMeta{
@@ -1133,7 +1163,12 @@ func handleCreateMattermostInstallation(c *Context, w http.ResponseWriter, r *ht
11331163
},
11341164
Database: mmv1beta1.Database{
11351165
External: &mmv1beta1.ExternalDatabase{
1136-
Secret: model.SecretNameDatabase,
1166+
Secret: func() string {
1167+
if databaseSecretName != "" {
1168+
return databaseSecretName
1169+
}
1170+
return model.SecretNameDatabase
1171+
}(),
11371172
},
11381173
},
11391174
FileStore: filestore,
@@ -1143,6 +1178,17 @@ func handleCreateMattermostInstallation(c *Context, w http.ResponseWriter, r *ht
11431178
{Name: model.MMENVLicense, ValueFrom: &v1.EnvVarSource{
11441179
SecretKeyRef: &v1.SecretKeySelector{Key: "license", LocalObjectReference: v1.LocalObjectReference{Name: licenseSecret.ObjectMeta.Name}, Optional: aws.Bool(true)}, // Add comma to separate items
11451180
}},
1181+
{Name: "MM_CONFIG", ValueFrom: &v1.EnvVarSource{
1182+
SecretKeyRef: &v1.SecretKeySelector{
1183+
Key: "MM_CONFIG",
1184+
LocalObjectReference: v1.LocalObjectReference{Name: func() string {
1185+
if databaseSecretName != "" {
1186+
return databaseSecretName
1187+
}
1188+
return model.SecretNameDatabase
1189+
}()},
1190+
},
1191+
}},
11461192
},
11471193
PodTemplate: &mmv1beta1.PodTemplate{
11481194
SecurityContext: &v1.PodSecurityContext{
@@ -1219,11 +1265,11 @@ func handleDeployMattermostOperator(c *Context, w http.ResponseWriter, r *http.R
12191265
}
12201266

12211267
chartSpec := helmclient.ChartSpec{
1222-
ReleaseName: "mattermost-operator",
1223-
ChartName: "mattermost/mattermost-operator",
1224-
Namespace: "mattermost-operator",
1225-
UpgradeCRDs: true,
1226-
Version: "v1.22.0",
1268+
ReleaseName: "mattermost-operator",
1269+
ChartName: "mattermost/mattermost-operator",
1270+
Namespace: "mattermost-operator",
1271+
UpgradeCRDs: true,
1272+
// Version: "1.25.2",
12271273
Wait: true,
12281274
Timeout: 300 * time.Second,
12291275
CreateNamespace: true,

api/context.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"github.com/mattermost/mattermost-cloudnative-bootstrapper/internal/logger"
1010
"github.com/mattermost/mattermost-cloudnative-bootstrapper/model"
1111
"github.com/mattermost/mattermost-cloudnative-bootstrapper/providers"
12-
"github.com/mattermost/mattermost-cloudnative-bootstrapper/telemetry"
1312
)
1413

1514
type BootstrapperState struct {
@@ -30,7 +29,6 @@ type Context struct {
3029
CloudProviderName string
3130
CloudProvider providers.CloudProvider
3231
BootstrapperState BootstrapperState
33-
TelemetryProvider *telemetry.TelemetryProvider
3432
}
3533

3634
func NewContext(ctx context.Context, statePath string, telemetryDisabled bool) (*Context, error) {
@@ -74,18 +72,11 @@ func NewContext(ctx context.Context, statePath string, telemetryDisabled bool) (
7472
}
7573
}
7674

77-
// Initialize the telemetry provider
78-
telemetryProvider, err := telemetry.NewTelemetryProvider(state.Telemetry.TelemetryID, state.Telemetry.TelemetryDisabled)
79-
if err != nil {
80-
return nil, err
81-
}
82-
8375
return &Context{
8476
Ctx: ctx,
8577
BootstrapperState: state,
8678
// TODO: this is redundant, use the state.Provider instead everywhere
8779
CloudProviderName: state.Provider,
88-
TelemetryProvider: telemetryProvider,
8980
}, nil
9081
}
9182

@@ -97,7 +88,6 @@ func (c *Context) Clone() *Context {
9788
CloudProviderName: c.CloudProviderName,
9889
CloudProvider: c.CloudProvider,
9990
BootstrapperState: c.BootstrapperState,
100-
TelemetryProvider: c.TelemetryProvider,
10191
}
10292
}
10393

api/response_writer_wrapper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (rw *ResponseWriterWrapper) Write(data []byte) (int, error) {
5252
// Hijack calls the underlying writer's Hijack output.
5353
func (rw *ResponseWriterWrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
5454
if rw.hijacker == nil {
55-
return nil, nil, errors.New("hijacker interface not supported by the wrapped ResponseWriter")
55+
return nil, nil, errors.New("Hijacker interface not supported by the wrapped ResponseWriter")
5656
}
5757
return rw.hijacker.Hijack()
5858
}

api/state.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ func initState(apiRouter *mux.Router, context *Context) {
1717

1818
stateRouter := apiRouter.PathPrefix("/state").Subrouter()
1919
stateRouter.Handle("/hydrate", addContext(handleHydrateState)).Methods("GET")
20+
stateRouter.Handle("/check", addContext(handleCheckState)).Methods("GET")
2021
stateRouter.Handle("", addContext(handlePatchState)).Methods("PATCH")
2122
}
2223

@@ -28,6 +29,42 @@ func handleHydrateState(c *Context, w http.ResponseWriter, r *http.Request) {
2829
json.NewEncoder(w).Encode(state)
2930
}
3031

32+
// SessionInfo represents a summary of an existing session for UI display
33+
type SessionInfo struct {
34+
Provider string `json:"provider"`
35+
ClusterName string `json:"clusterName"`
36+
HasState bool `json:"hasState"`
37+
}
38+
39+
func handleCheckState(c *Context, w http.ResponseWriter, r *http.Request) {
40+
w.Header().Set("Content-Type", "application/json")
41+
42+
// Check if a state file exists
43+
exists, err := CheckStateExists(c.BootstrapperState.StateFilePath)
44+
if err != nil {
45+
http.Error(w, err.Error(), http.StatusInternalServerError)
46+
return
47+
}
48+
49+
if !exists {
50+
// No state exists
51+
w.WriteHeader(http.StatusOK)
52+
json.NewEncoder(w).Encode(SessionInfo{HasState: false})
53+
return
54+
}
55+
56+
// State exists, return session info
57+
state := c.BootstrapperState
58+
sessionInfo := SessionInfo{
59+
Provider: state.Provider,
60+
ClusterName: state.ClusterName,
61+
HasState: true,
62+
}
63+
64+
w.WriteHeader(http.StatusOK)
65+
json.NewEncoder(w).Encode(sessionInfo)
66+
}
67+
3168
func handlePatchState(c *Context, w http.ResponseWriter, r *http.Request) {
3269
w.Header().Set("Content-Type", "application/json")
3370
w.WriteHeader(http.StatusOK)
@@ -156,3 +193,38 @@ func UpdateStateCredentials(existingState BootstrapperState, credentials *model.
156193

157194
return nil
158195
}
196+
197+
// UpdateStateCredentialsAndProvider updates credentials and provider in state
198+
func UpdateStateCredentialsAndProvider(existingState BootstrapperState, credentials *model.Credentials, provider string) error {
199+
state, err := GetState(existingState.StateFilePath)
200+
if err != nil {
201+
return err
202+
}
203+
204+
state.Credentials = credentials
205+
state.Provider = provider
206+
207+
err = SetState(existingState.StateFilePath, state)
208+
if err != nil {
209+
return err
210+
}
211+
212+
return nil
213+
}
214+
215+
// UpdateStateClusterName updates the cluster name in state
216+
func UpdateStateClusterName(existingState BootstrapperState, clusterName string) error {
217+
state, err := GetState(existingState.StateFilePath)
218+
if err != nil {
219+
return err
220+
}
221+
222+
state.ClusterName = clusterName
223+
224+
err = SetState(existingState.StateFilePath, state)
225+
if err != nil {
226+
return err
227+
}
228+
229+
return nil
230+
}

0 commit comments

Comments
 (0)