Skip to content

Commit b27f2dc

Browse files
authored
feat(notificationchannels): add team option in provider, add share_with_current_team in notification channels (#294)
* feat(notificationchannels): add team option in provider, add share_with_current_team in notification channels
1 parent fb6697d commit b27f2dc

36 files changed

+710
-162
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ jobs:
2525
test-sysdig:
2626
name: Sysdig Acceptance Tests
2727
runs-on: ubuntu-latest
28+
needs: test
2829

2930
steps:
3031
- name: Check out code

sysdig/common_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//go:build tf_acc_sysdig || tf_acc_ibm || unit
2+
3+
package sysdig_test
4+
5+
import (
6+
"os"
7+
"testing"
8+
)
9+
10+
func sysdigOrIBMMonitorPreCheck(t *testing.T) func() {
11+
return func() {
12+
monitor := os.Getenv("SYSDIG_MONITOR_API_TOKEN")
13+
ibmMonitor := os.Getenv("SYSDIG_IBM_MONITOR_API_KEY")
14+
if monitor == "" && ibmMonitor == "" {
15+
t.Fatal("SYSDIG_MONITOR_API_TOKEN or SYSDIG_IBM_MONITOR_API_KEY must be set for acceptance tests")
16+
}
17+
}
18+
}

sysdig/internal/client/v2/client.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"crypto/tls"
77
"encoding/json"
88
"errors"
9+
"fmt"
910
"github.com/hashicorp/go-retryablehttp"
1011
"github.com/jmespath/go-jmespath"
1112
"github.com/spf13/cast"
@@ -17,18 +18,24 @@ import (
1718
)
1819

1920
const (
21+
GetMePath = "/api/users/me"
2022
AuthorizationHeader = "Authorization"
2123
ContentTypeHeader = "Content-Type"
2224
ContentTypeJSON = "application/json"
2325
ContentTypeFormURLEncoded = "x-www-form-urlencoded"
2426
)
2527

28+
type Base interface {
29+
CurrentTeamID(ctx context.Context) (int, error)
30+
}
31+
2632
type Common interface {
2733
TeamInterface
2834
NotificationChannelInterface
2935
}
3036

3137
type Requester interface {
38+
CurrentTeamID(ctx context.Context) (int, error)
3239
Request(ctx context.Context, method string, url string, payload io.Reader) (*http.Response, error)
3340
}
3441

@@ -100,6 +107,39 @@ func request(httpClient *http.Client, cfg *config, request *http.Request) (*http
100107
return response, err
101108
}
102109

110+
func getMe(ctx context.Context, cfg *config, httpClient *http.Client, headers map[string]string) (*User, error) {
111+
r, err := http.NewRequest(
112+
http.MethodGet,
113+
fmt.Sprintf("%s%s", cfg.url, GetMePath),
114+
nil,
115+
)
116+
if err != nil {
117+
return nil, err
118+
}
119+
120+
r = r.WithContext(ctx)
121+
for k, v := range headers {
122+
r.Header.Set(k, v)
123+
}
124+
125+
resp, err := request(httpClient, cfg, r)
126+
if err != nil {
127+
return nil, err
128+
}
129+
defer resp.Body.Close()
130+
131+
wrapper, err := Unmarshal[userWrapper](resp.Body)
132+
if err != nil {
133+
return nil, err
134+
}
135+
136+
return &wrapper.User, nil
137+
}
138+
139+
func (client *Client) CurrentTeamID(ctx context.Context) (int, error) {
140+
return client.requester.CurrentTeamID(ctx)
141+
}
142+
103143
func newHTTPClient(cfg *config) *http.Client {
104144
httpClient := retryablehttp.NewClient()
105145
transport := http.DefaultTransport.(*http.Transport).Clone()

sysdig/internal/client/v2/config.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package v2
22

33
type config struct {
4-
url string
5-
token string
6-
insecure bool
7-
extraHeaders map[string]string
8-
ibmInstanceID string
9-
ibmAPIKey string
10-
ibmIamURL string
4+
url string
5+
token string
6+
insecure bool
7+
extraHeaders map[string]string
8+
ibmInstanceID string
9+
ibmAPIKey string
10+
ibmIamURL string
11+
sysdigTeamName string
12+
sysdigTeamID *int
1113
}
1214

1315
type ClientOption func(c *config)
@@ -54,6 +56,18 @@ func WithIBMIamURL(url string) ClientOption {
5456
}
5557
}
5658

59+
func WithSysdigTeamID(teamID *int) ClientOption {
60+
return func(c *config) {
61+
c.sysdigTeamID = teamID
62+
}
63+
}
64+
65+
func WithSysdigTeamName(teamName string) ClientOption {
66+
return func(c *config) {
67+
c.sysdigTeamName = teamName
68+
}
69+
}
70+
5771
func configure(opts ...ClientOption) *config {
5872
cfg := &config{}
5973
for _, opt := range opts {

sysdig/internal/client/v2/ibm.go

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66
"io"
77
"net/http"
88
"net/url"
9+
"strconv"
910
"strings"
11+
"sync"
1012
"time"
1113
)
1214

@@ -16,6 +18,8 @@ const (
1618
IBMGrantTypeFormValue = "grant_type"
1719
IBMApiKeyFormValue = "apikey"
1820
IBMAPIKeyGrantType = "urn:ibm:params:oauth:grant-type:apikey"
21+
SysdigTeamIDHeader = "SysdigTeamID"
22+
GetTeamByNamePath = "/api/v2/teams/light/name/"
1923
)
2024

2125
type IBMCommon interface {
@@ -30,10 +34,15 @@ type IBMAccessToken string
3034
type UnixTimestamp int64
3135

3236
type IBMRequest struct {
33-
config *config
34-
httpClient *http.Client
37+
config *config
38+
httpClient *http.Client
39+
40+
tokenLock *sync.Mutex
3541
tokenExpiration UnixTimestamp
3642
token IBMAccessToken
43+
44+
teamIDLock *sync.Mutex
45+
teamID *int
3746
}
3847

3948
type IAMTokenResponse struct {
@@ -42,6 +51,9 @@ type IAMTokenResponse struct {
4251
}
4352

4453
func (ir *IBMRequest) getIBMIAMToken() (IBMAccessToken, error) {
54+
ir.tokenLock.Lock()
55+
defer ir.tokenLock.Unlock()
56+
4557
if UnixTimestamp(time.Now().Unix()) < ir.tokenExpiration {
4658
return ir.token, nil
4759
}
@@ -75,6 +87,71 @@ func (ir *IBMRequest) getIBMIAMToken() (IBMAccessToken, error) {
7587
return ir.token, nil
7688
}
7789

90+
func (ir *IBMRequest) getTeamIDByName(ctx context.Context, name string, token IBMAccessToken) (int, error) {
91+
r, err := http.NewRequest(
92+
http.MethodGet,
93+
fmt.Sprintf("%s%s%s", ir.config.url, GetTeamByNamePath, name),
94+
nil,
95+
)
96+
if err != nil {
97+
return -1, err
98+
}
99+
100+
r = r.WithContext(ctx)
101+
r.Header.Set(IBMInstanceIDHeader, ir.config.ibmInstanceID)
102+
r.Header.Set(AuthorizationHeader, fmt.Sprintf("Bearer %s", token))
103+
104+
resp, err := request(ir.httpClient, ir.config, r)
105+
if err != nil {
106+
return -1, err
107+
}
108+
defer resp.Body.Close()
109+
110+
wrapper, err := Unmarshal[teamWrapper](resp.Body)
111+
if err != nil {
112+
return -1, err
113+
}
114+
115+
return wrapper.Team.ID, nil
116+
}
117+
118+
func (ir *IBMRequest) CurrentTeamID(ctx context.Context) (int, error) {
119+
ir.teamIDLock.Lock()
120+
defer ir.teamIDLock.Unlock()
121+
122+
if ir.teamID != nil {
123+
return *ir.teamID, nil
124+
}
125+
126+
token, err := ir.getIBMIAMToken()
127+
if err != nil {
128+
return -1, err
129+
}
130+
131+
if ir.config.sysdigTeamName != "" {
132+
teamID, err := ir.getTeamIDByName(ctx, ir.config.sysdigTeamName, token)
133+
if err != nil {
134+
return -1, err
135+
}
136+
137+
ir.teamID = &teamID
138+
return *ir.teamID, nil
139+
}
140+
141+
// use default current team
142+
user, err := getMe(ctx, ir.config, ir.httpClient, map[string]string{
143+
IBMInstanceIDHeader: ir.config.ibmInstanceID,
144+
AuthorizationHeader: fmt.Sprintf("Bearer %s", token),
145+
})
146+
if err != nil {
147+
return -1, err
148+
}
149+
150+
ir.teamID = &user.CurrentTeam
151+
152+
return *ir.teamID, nil
153+
}
154+
78155
func (ir *IBMRequest) Request(ctx context.Context, method string, url string, payload io.Reader) (*http.Response, error) {
79156
r, err := http.NewRequest(method, url, payload)
80157
if err != nil {
@@ -86,9 +163,15 @@ func (ir *IBMRequest) Request(ctx context.Context, method string, url string, pa
86163
return nil, err
87164
}
88165

166+
teamID, err := ir.CurrentTeamID(ctx)
167+
if err != nil {
168+
return nil, err
169+
}
170+
89171
r = r.WithContext(ctx)
90172
r.Header.Set(IBMInstanceIDHeader, ir.config.ibmInstanceID)
91173
r.Header.Set(AuthorizationHeader, fmt.Sprintf("Bearer %s", token))
174+
r.Header.Set(SysdigTeamIDHeader, strconv.Itoa(teamID))
92175
r.Header.Set(ContentTypeHeader, ContentTypeJSON)
93176

94177
return request(ir.httpClient, ir.config, r)
@@ -99,8 +182,11 @@ func newIBMClient(opts ...ClientOption) *Client {
99182
return &Client{
100183
config: cfg,
101184
requester: &IBMRequest{
185+
tokenLock: &sync.Mutex{},
186+
teamIDLock: &sync.Mutex{},
102187
config: cfg,
103188
httpClient: newHTTPClient(cfg),
189+
teamID: cfg.sysdigTeamID,
104190
},
105191
}
106192
}

0 commit comments

Comments
 (0)