Skip to content

Commit c002afe

Browse files
feat: separate org and cloud level auth
Signed-off-by: Ricky Moorhouse <[email protected]>
1 parent b7b4b0b commit c002afe

File tree

5 files changed

+79
-32
lines changed

5 files changed

+79
-32
lines changed

nets/apiconnect/apiconnect.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ var log = alog.UseChannel("apic")
3535

3636
func (a *APIConnect) crdStatusMetrics(group, version, resource string, crdStatus prometheus.GaugeVec) {
3737
subsystems := nets.GetCustomResourceList(group, version, resource, a.Config.Namespace)
38+
39+
// Check if subsystems is nil to prevent segmentation fault
40+
if subsystems == nil {
41+
log.Log(alog.DEBUG, "No %s resources found in namespace %s", resource, a.Config.Namespace)
42+
return
43+
}
3844

3945
for _, subsystem := range subsystems.Items {
4046
subsystemName := subsystem.Object["metadata"].(map[string]interface{})["name"].(string)

nets/main.go

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ type TokenResponse struct {
2929
ExpiresIn int `json:"expires_in"`
3030
}
3131

32+
type Token struct {
33+
Token string `json:"token"`
34+
Expires int `json:"expires"`
35+
}
36+
3237
type Client struct {
3338
Clientset kubernetes.Interface
3439
}
@@ -179,20 +184,17 @@ func GetCustomResourceList(group, version, resource, namespace string) *unstruct
179184
return items
180185
}
181186

182-
func GetToken(management_url string) (string, error) {
183-
return getNewToken(management_url)
184-
}
185-
186-
func getNewToken(management_url string) (string, error) {
187-
secretPath := os.Getenv(("MGMT_CREDS"))
187+
func GetToken(management_url string, secretPath string) (Token, error) {
188+
log.Log(alog.DEBUG, "Getting token using %s", secretPath)
188189
clientId, _ := os.ReadFile(filepath.Clean(secretPath + "/client_id"))
189190
clientSecret, _ := os.ReadFile(filepath.Clean(secretPath + "/client_secret"))
191+
apikey, _ := os.ReadFile(filepath.Clean(secretPath + "/apikey"))
190192
username, _ := os.ReadFile(filepath.Clean(secretPath + "/username"))
191193
password, _ := os.ReadFile(filepath.Clean(secretPath + "/password"))
192194
realm, _ := os.ReadFile(filepath.Clean(secretPath + "/realm"))
193195
var postBody []byte
194196
if (username != nil) && (password != nil) {
195-
log.Log(alog.DEBUG, "Username and password are set")
197+
log.Log(alog.DEBUG, "Using grant_type of password as username and password are set")
196198
postBody, _ = json.Marshal(map[string]string{
197199
"client_id": string(clientId),
198200
"client_secret": string(clientSecret),
@@ -201,7 +203,16 @@ func getNewToken(management_url string) (string, error) {
201203
"realm": string(realm),
202204
"grant_type": "password",
203205
})
206+
} else if apikey != nil {
207+
log.Log(alog.INFO, "Using grant_type of api_key")
208+
postBody, _ = json.Marshal(map[string]string{
209+
"client_id": string(clientId),
210+
"api_key": string(apikey),
211+
"client_secret": string(clientSecret),
212+
"grant_type": "api_key",
213+
})
204214
} else {
215+
log.Log(alog.INFO, "Using grant_type of client_credentials")
205216
postBody, _ = json.Marshal(map[string]string{
206217
"client_id": string(clientId),
207218
"client_secret": string(clientSecret),
@@ -223,23 +234,30 @@ func getNewToken(management_url string) (string, error) {
223234

224235
req, err := http.NewRequest("POST", url, tokenRequest)
225236
if err != nil {
226-
return "", err
237+
return Token{}, err
227238
} else {
228239
req.Header.Set("Content-Type", "application/json")
229240
req.Header.Set("Accept", "application/json")
230241
response, err := client.Do(req)
231242
if err != nil {
232243
log.Log(alog.ERROR, err.Error())
233-
return "", err
244+
return Token{}, err
234245
} else {
235246
defer response.Body.Close()
236-
var bearerToken TokenResponse
237-
err = json.NewDecoder(response.Body).Decode(&bearerToken)
238-
if err != nil {
239-
log.Log(alog.ERROR, err.Error())
240-
return "", err
247+
if response.StatusCode != 200 {
248+
return Token{}, fmt.Errorf("unexpected status - got %s, expected 200", response.Status)
249+
} else {
250+
var bearerToken TokenResponse
251+
err = json.NewDecoder(response.Body).Decode(&bearerToken)
252+
if err != nil {
253+
log.Log(alog.ERROR, err.Error())
254+
return Token{}, err
255+
}
256+
257+
return Token{
258+
Token: bearerToken.AccessToken,
259+
Expires: int(time.Now().Unix()) + bearerToken.ExpiresIn}, nil
241260
}
242-
return bearerToken.AccessToken, nil
243261
}
244262
}
245263
}

nets/main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestGetToken(t *testing.T) {
2121
}))
2222
defer server.Close()
2323

24-
token, err := GetToken(server.URL)
24+
token, err := GetToken(server.URL, "")
2525

2626
testLogger.Log(alog.DEBUG, "fetched token: %s", token)
2727
assert.Nil(err)

nets/manager/manager.go

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"nets"
7+
"os"
78
"strings"
89
"time"
910

@@ -14,9 +15,10 @@ import (
1415

1516
type Manager struct {
1617
nets.BaseNet
17-
Config ManagerNetConfig
18-
metrics map[string]*prometheus.GaugeVec
19-
token string
18+
Config ManagerNetConfig
19+
metrics map[string]*prometheus.GaugeVec
20+
cloudToken nets.Token
21+
orgToken nets.Token
2022
}
2123

2224
type ManagerNetConfig struct {
@@ -100,7 +102,6 @@ type ConfiguredGatewayService struct {
100102
var version string
101103

102104
var invokeAPI = nets.InvokeAPI
103-
var getToken = nets.GetToken
104105

105106
var log = alog.UseChannel("apim")
106107

@@ -127,9 +128,9 @@ func (m *Manager) registerMetrics() {
127128
func (m *Manager) getTopologyInfo(management_url string) (CloudTopology, error) {
128129

129130
url := fmt.Sprintf("%s/api/cloud/topology", management_url)
130-
log.Log(alog.DEBUG, url)
131+
log.Log(alog.DEBUG2, url)
131132

132-
response, err := invokeAPI(url, "", m.token)
133+
response, err := invokeAPI(url, "", m.cloudToken.Token)
133134
if err != nil {
134135
log.Log(alog.ERROR, err.Error())
135136
return CloudTopology{}, err
@@ -150,17 +151,17 @@ func (m *Manager) getTopologyInfo(management_url string) (CloudTopology, error)
150151
func (m *Manager) getWebhookStats(management_url string, org string, catalog string) {
151152
///api/catalogs/{}/{}/configured-gateway-services?fields=add(gateway_processing_status,events)
152153
url := fmt.Sprintf("%s/api/catalogs/%s/%s/configured-gateway-services?fields=add(gateway_processing_status,events)", management_url, org, catalog)
153-
log.Log(alog.DEBUG, url)
154+
log.Log(alog.DEBUG2, url)
154155

155-
response, err := invokeAPI(url, "", m.token)
156+
response, err := invokeAPI(url, "", m.orgToken.Token)
156157
if err != nil {
157158
log.Log(alog.ERROR, err.Error())
158159
return
159160
} else {
160161
defer response.Body.Close()
161162
var cgsResponse ConfiguredGatewayServices
162163
err = json.NewDecoder(response.Body).Decode(&cgsResponse)
163-
log.Log(alog.DEBUG, "Webhook status total results:", cgsResponse.TotalResults)
164+
log.Log(alog.DEBUG, "Webhook status total results: %v", cgsResponse.TotalResults)
164165
for _, cgs := range cgsResponse.Results {
165166
m.metrics["outstandingSent"].WithLabelValues(org, catalog, cgs.Name, cgs.ServiceVersion).Set(float64(cgs.GatewayProcessingStatus.OutstandingSentEvents))
166167
m.metrics["outstandingQueued"].WithLabelValues(org, catalog, cgs.Name, cgs.ServiceVersion).Set(float64(cgs.GatewayProcessingStatus.OutstandingQueuedEvents))
@@ -195,6 +196,33 @@ func (m *Manager) publishTopologyMetrics(topologyCount CountStruct, managementNa
195196
m.metrics["spaceGauge"].WithLabelValues(managementName, managementNamespace, scope, name).Set(topologyCount.Spaces)
196197
}
197198

199+
func (m *Manager) getTokens(management_url string) error {
200+
var err error
201+
202+
currentTimestamp := int(time.Now().Unix())
203+
204+
if m.cloudToken.Expires < currentTimestamp {
205+
m.cloudToken, err = nets.GetToken(management_url, os.Getenv(("MGMT_CREDS")))
206+
if err != nil {
207+
log.Log(alog.ERROR, err.Error())
208+
return err
209+
}
210+
} else {
211+
log.Log(alog.DEBUG, "Using cached cloud token")
212+
}
213+
if m.orgToken.Expires < currentTimestamp {
214+
m.orgToken, err = nets.GetToken(management_url, os.Getenv(("ORG_CREDS")))
215+
if err != nil {
216+
log.Log(alog.ERROR, err.Error())
217+
m.orgToken = m.cloudToken // If org creds are not set use cloud creds
218+
log.Log(alog.WARNING, "Using cloud token for org level API calls as org creds are not set")
219+
}
220+
} else {
221+
log.Log(alog.DEBUG, "Using cached org token")
222+
}
223+
return nil
224+
}
225+
198226
func (m *Manager) findAPIM() error {
199227

200228
apims := nets.GetCustomResourceList("management.apiconnect.ibm.com", "v1beta1", "managementclusters", m.Config.Namespace)
@@ -216,12 +244,7 @@ func (m *Manager) findAPIM() error {
216244
}
217245
log.Log(alog.INFO, "Override host set - using %s for manager", m.Config.Host)
218246
}
219-
var err error
220-
m.token, err = getToken(management_url)
221-
if err != nil {
222-
log.Log(alog.ERROR, err.Error())
223-
return err
224-
}
247+
m.getTokens(management_url)
225248
topology, err := m.getTopologyInfo(management_url)
226249
if err != nil {
227250
log.Log(alog.ERROR, err.Error())

nets/manager/manager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func MockCustomResourceList(group, version, resource string) *unstructured.Unstr
126126
return g
127127
}
128128

129-
func MockGetToken(url string) (string, error) {
129+
func MockGetToken(url string, path string) (string, error) {
130130
return "hello", nil
131131
}
132132

0 commit comments

Comments
 (0)