Skip to content

Commit 61ca17a

Browse files
committed
initial commit
0 parents  commit 61ca17a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+4160
-0
lines changed

.circleci/config.yml

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
version: 2
2+
jobs:
3+
build:
4+
docker:
5+
- image: circleci/golang
6+
7+
environment:
8+
TEST_RESULTS: /tmp/test-results
9+
GO111MODULE: "on"
10+
11+
steps:
12+
- checkout
13+
- run: mkdir -p $TEST_RESULTS
14+
- restore_cache:
15+
# Read about caching dependencies: https://circleci.com/docs/2.0/caching/
16+
keys:
17+
- go-mod-v4-{{ checksum "go.sum" }}
18+
19+
- run: go get github.com/jstemmer/go-junit-report
20+
- run: go get ./...
21+
- run:
22+
name: Run unit tests
23+
24+
# store the results of our tests in the $TEST_RESULTS directory
25+
command: |
26+
PACKAGE_NAMES=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname)
27+
gotestsum --junitfile ${TEST_RESULTS}/gotestsum-report.xml -- $PACKAGE_NAMES
28+
29+
- save_cache:
30+
key: go-mod-v4-{{ checksum "go.sum" }}
31+
paths:
32+
- "/go/pkg/mod"
33+
34+
- store_artifacts: # Upload test summary for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
35+
path: /tmp/test-results
36+
destination: raw-test-output
37+
38+
- store_test_results: # Upload test results for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
39+
path: /tmp/test-results
40+
41+
workflows:
42+
version: 2
43+
build-workflow:
44+
jobs:
45+
- build

.dockerignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.gitignore
2+
.git/
3+
k8s/example-*
4+
README.md

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
data
2+
config/config.json
3+
config/*.swp
4+
k8s/k8s-config.yaml
5+
vendor
6+
.vscode
7+
debug

LICENSE

+661
Large diffs are not rendered by default.

README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# f5-api
2+
3+
This API provides simple restful API access to a service.
4+
5+
## Endpoints
6+
7+
```
8+
GET /v1/test/ping
9+
GET /v1/test/version
10+
GET /v1/test/metrics
11+
```
12+
13+
## Authentication
14+
15+
Authentication is accomplished via an encrypted pre-shared key passed via the `X-Auth-Token` header.
16+
17+
## License
18+
19+
GNU Affero General Public License v3.0 (GNU AGPLv3)
20+
Copyright © 2021 Yale University

api/handlers.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package api
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/YaleSpinup/apierror"
9+
"github.com/pkg/errors"
10+
log "github.com/sirupsen/logrus"
11+
)
12+
13+
// PingHandler responds to ping requests
14+
func (s *server) PingHandler(w http.ResponseWriter, r *http.Request) {
15+
w = LogWriter{w}
16+
log.Debug("Ping/Pong")
17+
w.Header().Set("Access-Control-Allow-Origin", "*")
18+
w.WriteHeader(http.StatusOK)
19+
w.Write([]byte("pong"))
20+
}
21+
22+
// VersionHandler responds to version requests
23+
func (s *server) VersionHandler(w http.ResponseWriter, r *http.Request) {
24+
w = LogWriter{w}
25+
w.Header().Set("Access-Control-Allow-Origin", "*")
26+
w.Header().Set("Content-Type", "application/json")
27+
28+
data, err := json.Marshal(struct {
29+
Version string `json:"version"`
30+
GitHash string `json:"githash"`
31+
BuildStamp string `json:"buildstamp"`
32+
}{
33+
Version: fmt.Sprintf("%s%s", s.version.Version, s.version.VersionPrerelease),
34+
GitHash: s.version.GitHash,
35+
BuildStamp: s.version.BuildStamp,
36+
})
37+
38+
if err != nil {
39+
w.WriteHeader(http.StatusInternalServerError)
40+
w.Write([]byte{})
41+
return
42+
}
43+
44+
w.WriteHeader(http.StatusOK)
45+
w.Write(data)
46+
}
47+
48+
// handleError handles standard apierror return codes
49+
func handleError(w http.ResponseWriter, err error) {
50+
log.Error(err.Error())
51+
if aerr, ok := errors.Cause(err).(apierror.Error); ok {
52+
switch aerr.Code {
53+
case apierror.ErrForbidden:
54+
w.WriteHeader(http.StatusForbidden)
55+
case apierror.ErrNotFound:
56+
w.WriteHeader(http.StatusNotFound)
57+
case apierror.ErrConflict:
58+
w.WriteHeader(http.StatusConflict)
59+
case apierror.ErrBadRequest:
60+
w.WriteHeader(http.StatusBadRequest)
61+
case apierror.ErrLimitExceeded:
62+
w.WriteHeader(http.StatusTooManyRequests)
63+
default:
64+
w.WriteHeader(http.StatusInternalServerError)
65+
}
66+
w.Write([]byte(aerr.Message))
67+
} else {
68+
w.WriteHeader(http.StatusInternalServerError)
69+
w.Write([]byte(err.Error()))
70+
}
71+
}

api/handlers_ltm.go

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package api
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"net/http"
8+
9+
"github.com/YaleSpinup/apierror"
10+
"github.com/gorilla/mux"
11+
log "github.com/sirupsen/logrus"
12+
)
13+
14+
// ListClientSSLProfiles List Client SSL Profiles on LTM
15+
func (s *server) ListClientSSLProfiles(w http.ResponseWriter, r *http.Request) {
16+
w = LogWriter{w}
17+
vars := mux.Vars(r)
18+
host := vars["host"]
19+
20+
log.Infof("list client ssl profiles %s", host)
21+
22+
ltmService, ok := s.LTMServices[host]
23+
if !ok {
24+
msg := fmt.Sprintf("LTM host service not found for account: %s", host)
25+
handleError(w, apierror.New(apierror.ErrNotFound, msg, nil))
26+
return
27+
}
28+
29+
out, err := ltmService.ListClientSSLProfiles()
30+
if err != nil {
31+
handleError(w, err)
32+
return
33+
}
34+
35+
j, err := json.Marshal(out)
36+
if err != nil {
37+
handleError(w, apierror.New(apierror.ErrBadRequest, "failed to marshal json", err))
38+
return
39+
}
40+
41+
w.Header().Set("Content-Type", "application/json")
42+
w.WriteHeader(http.StatusOK)
43+
w.Write(j)
44+
}
45+
46+
// ShowClientSSLProfile Show detail of Client SSL Profile on LTM
47+
func (s *server) ShowClientSSLProfile(w http.ResponseWriter, r *http.Request) {
48+
w = LogWriter{w}
49+
vars := mux.Vars(r)
50+
host := vars["host"]
51+
name := vars["name"]
52+
53+
log.Infof("getting details about client ssl profile %s", name)
54+
55+
ltmService, ok := s.LTMServices[host]
56+
if !ok {
57+
msg := fmt.Sprintf("LTM host service not found for account: %s", host)
58+
handleError(w, apierror.New(apierror.ErrNotFound, msg, nil))
59+
return
60+
}
61+
62+
out, err := ltmService.GetClientSSLProfile(name)
63+
if err != nil {
64+
handleError(w, err)
65+
}
66+
67+
j, err := json.Marshal(out)
68+
if err != nil {
69+
handleError(w, apierror.New(apierror.ErrBadRequest, "failed to marshal json", err))
70+
return
71+
}
72+
73+
w.Header().Set("Content-Type", "application/json")
74+
w.WriteHeader(http.StatusOK)
75+
w.Write(j)
76+
}
77+
78+
// ModifyClientSSLProfile updates a clientssl profile including updating the cert and key if supplied in the body
79+
func (s *server) ModifyClientSSLProfile(w http.ResponseWriter, r *http.Request) {
80+
w = LogWriter{w}
81+
vars := mux.Vars(r)
82+
host := vars["host"]
83+
name := vars["name"]
84+
85+
log.Infof("updating client ssl profile")
86+
87+
raw, err := ioutil.ReadAll(r.Body)
88+
if err != nil {
89+
handleError(w, err)
90+
return
91+
}
92+
defer r.Body.Close()
93+
94+
data := ModifyClientSSLProfileRequest{}
95+
if err := json.Unmarshal(raw, &data); err != nil {
96+
handleError(w, err)
97+
}
98+
99+
ltmService, ok := s.LTMServices[host]
100+
if !ok {
101+
msg := fmt.Sprintf("LTM host service not found for account: %s", host)
102+
handleError(w, apierror.New(apierror.ErrNotFound, msg, nil))
103+
return
104+
}
105+
106+
orch := &ltmOrchestrator{
107+
client: ltmService,
108+
}
109+
110+
if err := orch.modifyClientSSLProfile(r.Context(), name, &data); err != nil {
111+
handleError(w, err)
112+
return
113+
}
114+
115+
out := fmt.Sprintf("ClientSSLProfile %s updated for host: %s\n", name, host)
116+
117+
w.Header().Set("Content-Type", "application/json")
118+
w.WriteHeader(http.StatusOK)
119+
w.Write([]byte(out))
120+
}
121+
122+
// CreateClientSSLProfile creates SSL Client Profile
123+
func (s *server) CreateClientSSLProfile(w http.ResponseWriter, r *http.Request) {
124+
w = LogWriter{w}
125+
vars := mux.Vars(r)
126+
host := vars["host"]
127+
name := vars["name"]
128+
129+
log.Infof("creating client ssl profile")
130+
131+
// data := MyClientSSLProfile{}
132+
133+
// err = json.Unmarshal([]byte(raw), &data)
134+
135+
raw, err := ioutil.ReadAll(r.Body)
136+
if err != nil {
137+
handleError(w, err)
138+
return
139+
}
140+
defer r.Body.Close()
141+
142+
data := ModifyClientSSLProfileRequest{}
143+
if err := json.Unmarshal(raw, &data); err != nil {
144+
handleError(w, err)
145+
}
146+
147+
ltmService, ok := s.LTMServices[host]
148+
if !ok {
149+
msg := fmt.Sprintf("LTM host service not found for account: %s", host)
150+
handleError(w, apierror.New(apierror.ErrNotFound, msg, nil))
151+
return
152+
}
153+
154+
orch := &ltmOrchestrator{
155+
client: ltmService,
156+
}
157+
158+
if err := orch.createClientSSLProfile(r.Context(), name, &data); err != nil {
159+
handleError(w, err)
160+
return
161+
}
162+
163+
out := fmt.Sprintf("SSLProfile %s created\n", name)
164+
165+
j, err := json.Marshal(out)
166+
if err != nil {
167+
handleError(w, apierror.New(apierror.ErrBadRequest, "failed to marshal json", err))
168+
return
169+
}
170+
171+
w.Header().Set("Content-Type", "application/json")
172+
w.WriteHeader(http.StatusOK)
173+
w.Write(j)
174+
}

api/handlers_ltm_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package api

0 commit comments

Comments
 (0)