Skip to content

Commit

Permalink
Search customer - replicated API
Browse files Browse the repository at this point in the history
Signed-off-by: Shanmugapriya <[email protected]>
  • Loading branch information
shanmugapriya-tr committed Jul 16, 2024
1 parent aa6de0c commit f98f4e3
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 4 deletions.
28 changes: 28 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/main.go",
"args": [
"start",
"--config",
"omnitruck.yml"
],
"env": {
"CONFIG": "arn:aws:secretsmanager:us-east-1:056914312429:secret:omnitruck-dev-config-NiDaz3",
"REGION": "us-east-1",
"AWS_ACCESS_KEY_ID": "YOUR_SECRET_HERE",
"AWS_SECRET_ACCESS_KEY": "YOUR_SECRET_HERE",
"AWS_SESSION_TOKEN": "YOUR_SECRET_HERE"
},
"cwd": "${workspaceFolder}"
}
]
}
58 changes: 58 additions & 0 deletions clients/omnitruck/replicated/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package replicated

type CustomerSearchResponse struct {
Query string `json:"query"`
TotalHits int `json:"total_hits"`
Customers []Customer `json:"customers"`
}

type GetCustomerResponse struct {
Customer Customer `json:"customer"`
}

type Customer struct {
ID string `json:"id"`
TeamID string `json:"teamId"`
Name string `json:"name"`
Email string `json:"email"`
CustomID string `json:"customId"`
ExpiresAt string `json:"expiresAt"`
CustomerType string `json:"type"`
Airgap bool `json:"airgap"`
InstallationId string `json:"installationId"`
Channels []Channel `json:"channels"`
}

type Channel struct {
ID string `json:"id"`
Name string `json:"name"`
AppID string `json:"appId"`
AppSlug string `json:"appSlug"`
AppName string `json:"appName"`
ChannelSlug string `json:"channelSlug"`
}

type EntitlementValues struct {
IsDefault bool `json:"isDefault"`
Name string `json:"name"`
Value string `json:"value"`
}

type RequestCustomer struct {
AppId string `json:"app_id"`
ChannelId string `json:"channel_id"`
Name string `json:"name"`
CustomerType string `json:"type"`
Email string `json:"email"`
EntitlementValues []EntitlementValues `json:"entitlementValues"`
ExpiresAt string `json:"expires_at"`
IsAirgapEnabled bool `json:"is_airgap_enabled"`
IsEmbeddedClusterDownloadEnabled bool `json:"is_embedded_cluster_download_enabled"`
IsGeoaxisSupported bool `json:"is_geoaxis_supported"`
IsGitopsSupported bool `json:"is_gitops_supported"`
IsHelmvmDownloadEnabled bool `json:"is_helmvm_download_enabled"`
IsIdentityServiceSupported bool `json:"is_identity_service_supported"`
IsKotsInstallEnabled bool `json:"is_kots_install_enabled"`
IsSnapshotSupported bool `json:"is_snapshot_supported"`
IsSupportBundleUploadEnabled bool `json:"is_support_bundle_upload_enabled"`
}
5 changes: 5 additions & 0 deletions clients/omnitruck/replicated/replicated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package replicated

type IReplicated interface {
SearchCustomersByEmail(email string, requestId string) (customers []Customer, err error)
}
107 changes: 107 additions & 0 deletions clients/omnitruck/replicated/replicated.impl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package replicated

import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"

"github.com/chef/omnitruck-service/config"
"github.com/chef/omnitruck-service/constants"
"github.com/chef/omnitruck-service/logger"
"github.com/chef/omnitruck-service/utils"
)

type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}

type ReplicatedImpl struct {
ReplicatedConfig config.ReplicatedConfig
Client HTTPClient
Logger logger.Logger
}

func NewReplicatedImpl(config config.ReplicatedConfig, logger logger.Logger) IReplicated {
return &ReplicatedImpl{
Client: &http.Client{},
ReplicatedConfig: config,
Logger: logger,
}
}

var ReadFile = func(r io.Reader) ([]byte, error) {
return io.ReadAll(r)
}

var NewRequest = func(method string, url string, payload io.Reader) (res *http.Request, err error) {
return http.NewRequest(method, url, payload)
}

func (r ReplicatedImpl) makeRequest(url, method, requestId string, payload io.Reader) (int, []byte, error) {
log := utils.AddLogFields("makeRequest", requestId, r.Logger)

req, err := NewRequest(method, url, payload)
if err != nil {
log.Errorln("error in creating new request.\n[ERROR] -", err.Error())
return 0, nil, err
}

req.Header.Add("accept", "application/json")
req.Header.Add("content-type", "application/json")
req.Header.Add("Authorization", r.ReplicatedConfig.Token)

res, err := r.Client.Do(req)
if err != nil {
log.Errorln("error on response.\n[ERROR] -", err.Error())
return 0, nil, err
}

defer res.Body.Close()
body, err := ReadFile(res.Body)
if err != nil {
log.Errorln("error on reading body.\n[ERROR] -", err.Error())
return 0, nil, err
}
return res.StatusCode, body, nil
}

func (r ReplicatedImpl) SearchCustomersByEmail(email string, requestId string) (customers []Customer, err error) {
log := utils.AddLogFields("SearchCustomersByEmail", requestId, r.Logger)

url := fmt.Sprintf("%s/customers/search", r.ReplicatedConfig.URL)
method := http.MethodPost

payload := strings.NewReader(fmt.Sprintf(`{
"app_id": "%s",
"include_trial": true,
"include_community": true,
"include_paid": true,
"include_dev": true,
"include_active": true,
"include_inactive": true,
"query": "email:%s"
}`, r.ReplicatedConfig.AppID, email))

respStatusCode, respBody, err := r.makeRequest(url, method, requestId, payload)
if err != nil {
log.Errorln("failed to search the customer: ", err.Error())
return nil, err
}

if respStatusCode != http.StatusOK {
err = fmt.Errorf("search customers by email failed with statusCode %d", respStatusCode)
log.Errorln("error on search customers by email.\n[ERROR] -", err.Error())
return nil, err
}

var respObj CustomerSearchResponse
err = json.Unmarshal(respBody, &respObj)
if err != nil {
log.Errorln(constants.UNMARSHAL_ERR_MSG, err.Error())
return nil, err
}

return respObj.Customers, nil
}
88 changes: 88 additions & 0 deletions clients/omnitruck/replicated/replicated.impl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package replicated_test

import (
"bytes"
"fmt"
"io"
"net/http"
"testing"

"github.com/chef/omnitruck-service/clients/omnitruck/replicated"
"github.com/chef/omnitruck-service/config"
"github.com/chef/omnitruck-service/logger"
"github.com/stretchr/testify/assert"
)

type MockClient struct {
DoFunc func(req *http.Request) (*http.Response, error)
}

func (mc MockClient) Do(req *http.Request) (*http.Response, error) {
return mc.DoFunc(req)
}

func TestSearchCustomerByEmailSuccess(t *testing.T) {
repImp := replicated.ReplicatedImpl{
Client: &MockClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
responseBody := io.NopCloser(bytes.NewReader([]byte(`{
"query": "email:[email protected]",
"total_hits": 1,
"customers": [
{
"id": "2eDnZGGGSjwJN91WZh74A",
"teamId": "6IopgEQswci9pZWVGGNHU4NyoRbaWe7d",
"name": "[DEV] Test",
"email": "[email protected]",
"customId": ""
}
]
}`)))
return &http.Response{
StatusCode: 200,
Body: responseBody,
}, nil
},
},
ReplicatedConfig: config.ReplicatedConfig{},
Logger: logger.NewLogrusStandardLogger(),
}
customers, err := repImp.SearchCustomersByEmail("[email protected]", "")
assert.NoError(t, err)
assert.Equal(t, 1, len(customers))

}

func TestSearchCustomerByEmailError(t *testing.T) {
repImp := replicated.ReplicatedImpl{
Client: &MockClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("catastrophic failure")
},
},
ReplicatedConfig: config.ReplicatedConfig{},
Logger: logger.NewLogrusStandardLogger(),
}
_, err := repImp.SearchCustomersByEmail("[email protected]", "")
assert.Error(t, err)
}

func TestSearchCustomerByEmail500(t *testing.T) {
repImp := replicated.ReplicatedImpl{
Client: &MockClient{
DoFunc: func(req *http.Request) (*http.Response, error) {
responseBody := io.NopCloser(bytes.NewReader([]byte(`{
"message": "error occurred"
}`)))
return &http.Response{
StatusCode: 500,
Body: responseBody,
}, nil
},
},
ReplicatedConfig: config.ReplicatedConfig{},
Logger: logger.NewLogrusStandardLogger(),
}
_, err := repImp.SearchCustomersByEmail("[email protected]", "")
assert.Error(t, err)
}
9 changes: 9 additions & 0 deletions clients/omnitruck/replicated/replicated.mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package replicated

type MockReplicated struct {
SearchCustomersByEmailFunc func(email string, requestId string) (customers []Customer, err error)
}

func (m MockReplicated) SearchCustomersByEmail(email string, requestId string) (customers []Customer, err error) {
return m.SearchCustomersByEmailFunc(email, requestId)
}
15 changes: 11 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package config

type ServiceConfig struct {
LicenseServiceUrl string `json:"licenseServiceUrl"`
RelatedProductsTable string `json:"relatedProductsTable"`
MetadataDetailsTable string `json:"metadataDetailsTable"`
AWSConfig AWSConfig `json:"awsConfig"`
LicenseServiceUrl string `json:"licenseServiceUrl"`
RelatedProductsTable string `json:"relatedProductsTable"`
MetadataDetailsTable string `json:"metadataDetailsTable"`
AWSConfig AWSConfig `json:"awsConfig"`
ReplicatedConfig ReplicatedConfig `json:"replicatedConfig"`
}

type ReplicatedConfig struct {
URL string `json:"url"`
Token string `json:"token"`
AppID string `json:"appId"`
}

type AWSConfig struct {
Expand Down
4 changes: 4 additions & 0 deletions constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ const (
HABITAT_PRODUCT = "habitat"
LATEST = "latest"
)

const (
UNMARSHAL_ERR_MSG = "error on unmarshal.\n[ERROR] -"
)
57 changes: 57 additions & 0 deletions logger/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package logger

import (
"strings"

"github.com/sirupsen/logrus"
)

type Logger interface {
logrus.FieldLogger
}

type wrap struct {
*logrus.Logger
}

const (
LogFormatJSON = "json"
LogFormatText = "text"
)

func NewLogrusStandardLogger() Logger {
return &wrap{Logger: logrus.StandardLogger()}
}

// SetupLogger to setup log config
func SetupLogger(level string, out, format string, debug bool) (Logger, error) {

l := logrus.StandardLogger()
logLevel, err := logrus.ParseLevel(level)
if err != nil {
return nil, err
}
l.SetLevel(logLevel)

var formatter logrus.Formatter
switch strings.ToLower(format) {
case LogFormatJSON:
formatter = &logrus.JSONFormatter{
TimestampFormat: "2006-01-02T15:04:05.000",
}
if debug {
formatter.(*logrus.JSONFormatter).PrettyPrint = true
}
case LogFormatText:
formatter = &logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02T15:04:05.000Z",
}
}
if debug {
l.SetReportCaller(true)
}

l.SetFormatter(formatter)
return &wrap{Logger: l}, nil
}
Loading

0 comments on commit f98f4e3

Please sign in to comment.