Skip to content

Commit e48958f

Browse files
authored
Connect marketplace API to microservice (#2130)
1 parent 63e2793 commit e48958f

File tree

9 files changed

+183
-46
lines changed

9 files changed

+183
-46
lines changed

.goreleaser.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ builds:
4444
- --tags=kqueue,operator
4545

4646
ldflags:
47-
- -s -w -X github.com/minio/console/pkg.ReleaseTag={{.Tag}} -X github.com/minio/console/pkg.CommitID={{.FullCommit}} -X github.com/minio/console/pkg.Version={{.Version}} -X github.com/minio/console/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/console/pkg.ReleaseTime={{.Date}}
47+
- -s -w -X github.com/minio/console/pkg.ReleaseTag={{.Tag}} -X github.com/minio/console/pkg.CommitID={{.FullCommit}} -X github.com/minio/console/pkg.Version={{.Version}} -X github.com/minio/console/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/console/pkg.ReleaseTime={{.Date}} -X github.com/minio/console/pkg.MPSecret={{.Env.MPSECRET}}
4848

4949
archives:
5050
-

models/mp_integration.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

operatorapi/embedded_spec.go

Lines changed: 18 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

operatorapi/marketplace.go

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// This file is part of MinIO Console Server
2-
// Copyright (c) 2021 MinIO, Inc.
2+
// Copyright (c) 2022 MinIO, Inc.
33
//
44
// This program is free software: you can redistribute it and/or modify
55
// it under the terms of the GNU Affero General Public License as published by
@@ -19,22 +19,33 @@ package operatorapi
1919
import (
2020
"context"
2121
"fmt"
22+
"io"
23+
"net/http"
2224
"os"
25+
"strings"
26+
"time"
2327

2428
"github.com/go-openapi/runtime/middleware"
29+
"github.com/golang-jwt/jwt/v4"
2530
"github.com/minio/console/cluster"
2631
"github.com/minio/console/models"
2732
"github.com/minio/console/operatorapi/operations"
2833
"github.com/minio/console/operatorapi/operations/operator_api"
34+
"github.com/minio/console/pkg"
2935
errors "github.com/minio/console/restapi"
36+
"github.com/minio/pkg/env"
3037
corev1 "k8s.io/api/core/v1"
3138
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3239
)
3340

3441
var (
3542
mpConfigMapDefault = "mp-config"
3643
mpConfigMapKey = "MP_CONFIG_KEY"
37-
mpEmail = "email"
44+
mpHostEnvVar = "MP_HOST"
45+
defaultMPHost = "https://marketplace.apps.min.dev"
46+
mpEUHostEnvVar = "MP_EU_HOST"
47+
defaultEUMPHost = "https://marketplace-eu.apps.min.dev"
48+
isMPEmailSet = "isEmailSet"
3849
emailNotSetMsg = "Email was not sent in request"
3950
)
4051

@@ -56,62 +67,112 @@ func registerMarketplaceHandlers(api *operations.OperatorAPI) {
5667
})
5768
}
5869

59-
func getMPIntegrationResponse(session *models.Principal, params operator_api.GetMPIntegrationParams) (*models.MpIntegration, *models.Error) {
60-
if true { // This block will be removed once service to register emails is deployed
61-
return nil, &models.Error{Code: 501}
62-
}
70+
func getMPIntegrationResponse(session *models.Principal, params operator_api.GetMPIntegrationParams) (*operator_api.GetMPIntegrationOKBody, *models.Error) {
6371
clientSet, err := cluster.K8sClient(session.STSSessionToken)
6472
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
6573
defer cancel()
6674
if err != nil {
6775
return nil, errors.ErrorWithContext(ctx, err)
6876
}
69-
mpEmail, err := getMPEmail(ctx, &k8sClient{client: clientSet})
77+
isMPEmailSet, err := getMPEmail(ctx, &k8sClient{client: clientSet})
7078
if err != nil {
7179
return nil, errors.ErrorWithContext(ctx, errors.ErrNotFound)
7280
}
73-
return &models.MpIntegration{
74-
Email: mpEmail,
81+
return &operator_api.GetMPIntegrationOKBody{
82+
IsEmailSet: isMPEmailSet,
7583
}, nil
7684
}
7785

78-
func getMPEmail(ctx context.Context, clientSet K8sClientI) (string, error) {
86+
func getMPEmail(ctx context.Context, clientSet K8sClientI) (bool, error) {
7987
cm, err := clientSet.getConfigMap(ctx, "default", getMPConfigMapKey(mpConfigMapKey), metav1.GetOptions{})
8088
if err != nil {
81-
return "", err
89+
return false, err
8290
}
83-
return cm.Data[mpEmail], nil
91+
return cm.Data[isMPEmailSet] == "true", nil
8492
}
8593

8694
func postMPIntegrationResponse(session *models.Principal, params operator_api.PostMPIntegrationParams) *models.Error {
87-
if true { // This block will be removed once service to register emails is deployed
88-
return &models.Error{Code: 501}
89-
}
9095
clientSet, err := cluster.K8sClient(session.STSSessionToken)
9196
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
9297
defer cancel()
9398
if err != nil {
9499
return errors.ErrorWithContext(ctx, err)
95100
}
96-
return setMPIntegration(ctx, params.Body.Email, &k8sClient{client: clientSet})
101+
return setMPIntegration(ctx, params.Body.Email, params.Body.IsInEU, &k8sClient{client: clientSet})
97102
}
98103

99-
func setMPIntegration(ctx context.Context, email string, clientSet K8sClientI) *models.Error {
104+
func setMPIntegration(ctx context.Context, email string, isInEU bool, clientSet K8sClientI) *models.Error {
100105
if email == "" {
101106
return errors.ErrorWithContext(ctx, errors.ErrBadRequest, fmt.Errorf(emailNotSetMsg))
102107
}
103-
if _, err := setMPEmail(ctx, email, clientSet); err != nil {
108+
if _, err := setMPEmail(ctx, email, isInEU, clientSet); err != nil {
104109
return errors.ErrorWithContext(ctx, err)
105110
}
106111
return nil
107112
}
108113

109-
func setMPEmail(ctx context.Context, email string, clientSet K8sClientI) (*corev1.ConfigMap, error) {
110-
cm := createCM(email)
114+
func setMPEmail(ctx context.Context, email string, isInEU bool, clientSet K8sClientI) (*corev1.ConfigMap, error) {
115+
if err := postEmailToMP(email, isInEU); err != nil {
116+
return nil, err
117+
}
118+
cm := createCM()
111119
return clientSet.createConfigMap(ctx, "default", cm, metav1.CreateOptions{})
112120
}
113121

114-
func createCM(email string) *corev1.ConfigMap {
122+
func postEmailToMP(email string, isInEU bool) error {
123+
mpURL, err := getMPURL(isInEU)
124+
if err != nil {
125+
return err
126+
}
127+
return makePostRequestToMP(mpURL, email)
128+
}
129+
130+
func getMPURL(isInEU bool) (string, error) {
131+
mpHost := getMPHost(isInEU)
132+
if mpHost == "" {
133+
return "", fmt.Errorf("mp host not set")
134+
}
135+
return fmt.Sprintf("%s/mp-email", mpHost), nil
136+
}
137+
138+
func getMPHost(isInEU bool) string {
139+
if isInEU {
140+
return env.Get(mpEUHostEnvVar, defaultEUMPHost)
141+
}
142+
return env.Get(mpHostEnvVar, defaultMPHost)
143+
}
144+
145+
func makePostRequestToMP(url, email string) error {
146+
request, err := createMPRequest(url, email)
147+
if err != nil {
148+
return err
149+
}
150+
client := &http.Client{Timeout: 3 * time.Second}
151+
if res, err := client.Do(request); err != nil {
152+
return err
153+
} else if res.StatusCode >= http.StatusBadRequest {
154+
b, _ := io.ReadAll(res.Body)
155+
return fmt.Errorf("request to %s failed with status code %d and error %s", url, res.StatusCode, string(b))
156+
}
157+
return nil
158+
}
159+
160+
func createMPRequest(url, email string) (*http.Request, error) {
161+
request, err := http.NewRequest("POST", url, strings.NewReader(fmt.Sprintf("{\"email\":\"%s\"}", email)))
162+
if err != nil {
163+
return nil, err
164+
}
165+
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{})
166+
jwtTokenString, err := jwtToken.SignedString([]byte(pkg.MPSecret))
167+
if err != nil {
168+
return nil, err
169+
}
170+
request.Header.Add("Cookie", fmt.Sprintf("jwtToken=%s", jwtTokenString))
171+
request.Header.Add("Content-Type", "application/json")
172+
return request, nil
173+
}
174+
175+
func createCM() *corev1.ConfigMap {
115176
return &corev1.ConfigMap{
116177
TypeMeta: metav1.TypeMeta{
117178
Kind: "ConfigMap",
@@ -121,7 +182,7 @@ func createCM(email string) *corev1.ConfigMap {
121182
Name: getMPConfigMapKey(mpConfigMapKey),
122183
Namespace: "default",
123184
},
124-
Data: map[string]string{mpEmail: email},
185+
Data: map[string]string{isMPEmailSet: "true"},
125186
}
126187
}
127188

operatorapi/marketplace_test.go

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func (suite *MarketplaceTestSuite) getConfigMapMock(ctx context.Context, namespa
8282
if testWithError {
8383
return nil, errMock
8484
}
85-
return &corev1.ConfigMap{Data: map[string]string{mpEmail: "mock@mock.com"}}, nil
85+
return &corev1.ConfigMap{Data: map[string]string{isMPEmailSet: "true"}}, nil
8686
}
8787

8888
func (suite *MarketplaceTestSuite) createConfigMapMock(ctx context.Context, namespace string, cm *corev1.ConfigMap, opts metav1.CreateOptions) (*corev1.ConfigMap, error) {
@@ -115,11 +115,6 @@ func (suite *MarketplaceTestSuite) TestRegisterMarketplaceHandlers() {
115115
suite.assert.NotNil(api.OperatorAPIPostMPIntegrationHandler)
116116
}
117117

118-
// TODO
119-
// WIP - Complete successful tests to RUD handlers
120-
// WIP - Add tests to POST handler
121-
// WIP - Check how to mock k8s objects for tests with no error
122-
123118
func (suite *MarketplaceTestSuite) TestGetMPIntegrationHandlerWithError() {
124119
api := &operations.OperatorAPI{}
125120
registerMarketplaceHandlers(api)
@@ -130,6 +125,19 @@ func (suite *MarketplaceTestSuite) TestGetMPIntegrationHandlerWithError() {
130125
suite.assert.True(ok)
131126
}
132127

128+
func (suite *MarketplaceTestSuite) TestPostMPIntegrationHandlerWithError() {
129+
api := &operations.OperatorAPI{}
130+
registerMarketplaceHandlers(api)
131+
params := operator_api.NewPostMPIntegrationParams()
132+
params.Body = &models.MpIntegration{Email: ""}
133+
params.HTTPRequest = &http.Request{}
134+
params.HTTPRequest.Header = map[string][]string{}
135+
params.HTTPRequest.AddCookie(&http.Cookie{Value: "token", Name: "token"})
136+
response := api.OperatorAPIPostMPIntegrationHandler.Handle(params, &models.Principal{})
137+
_, ok := response.(*operator_api.PostMPIntegrationDefault)
138+
suite.assert.True(ok)
139+
}
140+
133141
func (suite *MarketplaceTestSuite) TestGetMPEmailWithError() {
134142
testWithError = true
135143
ctx, cancel := context.WithCancel(context.Background())
@@ -143,33 +151,36 @@ func (suite *MarketplaceTestSuite) TestGetMPEmailNoError() {
143151
testWithError = false
144152
ctx, cancel := context.WithCancel(context.Background())
145153
defer cancel()
146-
email, err := getMPEmail(ctx, &suite.kClient)
154+
isSet, err := getMPEmail(ctx, &suite.kClient)
147155
suite.assert.Nil(err)
148-
suite.assert.NotEmpty(email)
156+
suite.assert.True(isSet)
149157
}
150158

151159
func (suite *MarketplaceTestSuite) TestSetMPIntegrationNoEmail() {
152160
ctx, cancel := context.WithCancel(context.Background())
153161
defer cancel()
154-
err := setMPIntegration(ctx, "", &suite.kClient)
162+
err := setMPIntegration(ctx, "", false, &suite.kClient)
155163
suite.assert.NotNil(err)
156164
}
157165

158166
func (suite *MarketplaceTestSuite) TestSetMPIntegrationWithError() {
159167
testWithError = true
160168
ctx, cancel := context.WithCancel(context.Background())
161169
defer cancel()
162-
err := setMPIntegration(ctx, "mock@mock.com", &suite.kClient)
170+
os.Setenv(mpHostEnvVar, " ")
171+
err := setMPIntegration(ctx, "mock@mock.com", false, &suite.kClient)
163172
suite.assert.NotNil(err)
173+
os.Unsetenv(mpHostEnvVar)
164174
}
165175

166-
func (suite *MarketplaceTestSuite) TestSetMPIntegrationNoError() {
167-
testWithError = false
168-
ctx, cancel := context.WithCancel(context.Background())
169-
defer cancel()
170-
err := setMPIntegration(ctx, "mock@mock.com", &suite.kClient)
171-
suite.assert.Nil(err)
172-
}
176+
// TODO: Add mock server for testing microservice
177+
// func (suite *MarketplaceTestSuite) TestSetMPIntegrationNoError() {
178+
// testWithError = false
179+
// ctx, cancel := context.WithCancel(context.Background())
180+
// defer cancel()
181+
// err := setMPIntegration(ctx, "mock@mock.com", "token", &suite.kClient)
182+
// suite.assert.Nil(err)
183+
// }
173184

174185
func TestMarketplace(t *testing.T) {
175186
suite.Run(t, new(MarketplaceTestSuite))

operatorapi/operations/operator_api/get_m_p_integration.go

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)