Skip to content
This repository was archived by the owner on Aug 21, 2025. It is now read-only.

Commit 8ee49f6

Browse files
authored
Merge pull request #133 from GSA-TTS/zjr/ssh-map_route-int_setup
Go CFD: SSH, Map Route, Integration Test Setup & Teardown
2 parents 11cb8d9 + cc91626 commit 8ee49f6

23 files changed

Lines changed: 791 additions & 203 deletions

.github/workflows/cf-driver-go.yml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ name: "CF Driver: Go Build & Test"
55

66
on: [pull_request]
77

8-
defaults:
9-
run:
10-
working-directory: runner-manager/cfd
11-
128
jobs:
139
build:
1410
runs-on: ubuntu-latest
@@ -17,12 +13,9 @@ jobs:
1713

1814
- name: Set up Go
1915
uses: actions/setup-go@v5
20-
with:
21-
go-version-file: runner-manager/cfd/go.mod
22-
cache-dependency-path: runner-manager/cfd/go.sum
2316

2417
- name: Install dependencies
25-
run: go get .
18+
run: go get ./...
2619

2720
- name: Check formatting
2821
run: test -z "$(gofmt -l .)"

.lazy.lua

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
return {
2+
{
3+
"nvim-neotest/neotest",
4+
config = function()
5+
---@diagnostic disable-next-line: missing-fields
6+
require("neotest").setup({
7+
adapters = {
8+
require("neotest-golang")({
9+
go_test_args = { "-v", "-race", "-count=1", "-tags=integration" },
10+
go_list_args = { "-tags=integration" },
11+
dap_go_opts = {
12+
delve = {
13+
build_flags = { "-tags=integration" },
14+
},
15+
},
16+
}),
17+
},
18+
})
19+
end,
20+
},
21+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ vet: fmt
88
go vet ./...
99

1010
test: vet
11-
go test ./...
11+
go test -v ./...
1212

1313
integration: vet
14-
go test -count=1 --tags=integration ./...
14+
go test -v -count=1 --tags=integration ./...
1515

1616
build: vet
17-
go build
17+
go build ./runner-manager/cfd
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/GSA-TTS/gitlab-runner-cloudgov/runner/cfd
1+
module github.com/GSA-TTS/gitlab-runner-cloudgov
22

33
go 1.23.5
44

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,7 @@ golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht
4545
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
4646
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
4747
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
48+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
49+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
4850
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
4951
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

runner-manager/cfd/.vscode/launch.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

runner-manager/cfd/README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ make test
5050

5151
### Integration tests
5252

53-
We only have one integration test right now, and to get it running you'll need to do a bit of local setup.
54-
55-
1. You will need to first get a username & password for some space on cloud.gov that has at least one app.
56-
1. Then you can add those credentials to `./cg/testdata/.cg_creds` in the style of the `.cg_creds.sample` file there.
57-
1. Run the test with `make integration`, which should give you an error and, in its output, show you what the resulting JSON looks like.
58-
1. Copy that JSON result over to the last line of your `.cg_creds` file and run `make integration` again, this time it should succeed.
53+
Integration tests take a little effort get working.
54+
55+
1. Set your `cf target` to `sandbox-gsa`.
56+
2. Run `./sh/integration_setup.sh`.
57+
a. This will output credentials and `cf target` info to the `testdata` directories for `./cloudgov` and `./cmd/drive`.
58+
b. It will also create a sample app in your sandbox account to be used for testing.
59+
3. Run integration tests with `make integration`
60+
4. Whenever you're ready, you can clean up the credentials & app made during setup with `./sh/integration_teardown.sh`.
5961

6062
## Builds
6163

runner-manager/cfd/cloudgov/cf_client.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func castApp(app *resource.App) *App {
7373
if app == nil || app.GUID == "" {
7474
return nil
7575
}
76-
return &(App{Name: app.Name, GUID: app.GUID, State: app.State})
76+
return &(App{Name: app.Name, GUID: app.GUID, State: app.State, SpaceGUID: app.Relationships.Space.Data.GUID})
7777
}
7878

7979
func castApps(apps []*resource.App) []*App {
@@ -104,3 +104,35 @@ func (cf *CFClientAPI) appsList() ([]*App, error) {
104104
}
105105
return castApps(apps), nil
106106
}
107+
108+
func (cf *CFClientAPI) sshCode() (string, error) {
109+
ctx := context.Background()
110+
return cf.conn().SSHCode(ctx)
111+
}
112+
113+
func (cf *CFClientAPI) mapRoute(
114+
ctx context.Context,
115+
app *App,
116+
domain string, space string, host string, path string, port int,
117+
) error {
118+
opts := resource.NewRouteCreateWithHost(domain, space, host, path, port)
119+
120+
route, err := cf.conn().Routes.Create(ctx, opts)
121+
if err != nil {
122+
return err
123+
}
124+
125+
_, err = cf.conn().Routes.InsertDestinations(
126+
ctx,
127+
route.GUID,
128+
[]*resource.RouteDestinationInsertOrReplace{{
129+
App: resource.RouteDestinationApp{GUID: &app.GUID},
130+
}},
131+
)
132+
return err
133+
}
134+
135+
// addNetworkPolicy implements ClientAPI.
136+
func (cf *CFClientAPI) addNetworkPolicy(app *App, dest string, space string, port string) error {
137+
panic("unimplemented")
138+
}

runner-manager/cfd/cloudgov/cloudgov.go

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
package cloudgov
22

3-
import (
4-
"errors"
5-
"fmt"
3+
import "context"
64

7-
"github.com/cloudfoundry/go-cfclient/v3/resource"
8-
)
9-
10-
// Stuff we'll need to implement, for ref
11-
//
12-
// mapRoute()
13-
//
14-
// addNetworkPolicy()
15-
// removeNetworkPolicy()
165
type ClientAPI interface {
176
connect(url string, creds *Creds) error
187

198
appGet(id string) (*App, error)
209
appPush(m *AppManifest) (*App, error)
2110
appDelete(id string) error
2211
appsList() (apps []*App, err error)
12+
13+
sshCode() (string, error)
14+
mapRoute(ctx context.Context, app *App, domain string, space string, host string, path string, port int) error
15+
addNetworkPolicy(app *App, dest string, space string, port string) error
2316
}
2417

2518
type CredsGetter interface {
@@ -46,8 +39,10 @@ func (e CloudGovClientError) Error() string {
4639
return e.msg
4740
}
4841

49-
// TODO: we should pull this out of VCAP_APPLICATION
50-
const apiRootURLDefault = "https://api.fr.cloud.gov"
42+
const (
43+
apiRootURLDefault = "https://api.fr-stage.cloud.gov"
44+
internalDomainGUID = "8a5d6a8c-cfc1-4fc4-afc9-aa563ff9df5e"
45+
)
5146

5247
func New(i ClientAPI, o *Opts) (*Client, error) {
5348
if o == nil {
@@ -83,9 +78,10 @@ func (c *Client) Connect() (*Client, error) {
8378
}
8479

8580
type App struct {
86-
Name string
87-
GUID string
88-
State string
81+
Name string
82+
GUID string
83+
State string
84+
SpaceGUID string
8985
}
9086

9187
func (c *Client) AppGet(id string) (*App, error) {
@@ -102,34 +98,15 @@ func (c *Client) AppsList() ([]*App, error) {
10298

10399
// TODO: this abstraction might belong in /cmd,
104100
// unless it can be further generalized to all pushes
105-
func (c *Client) ServicePush(manifest *AppManifest) (*App, error) {
101+
func (c *Client) Push(manifest *AppManifest) (*App, error) {
106102
containerID := manifest.Name
107103

108104
if containerID == "" {
109-
return nil, CloudGovClientError{"ServicePush: AppManifest.Name must be defined"}
105+
return nil, CloudGovClientError{"Push: AppManifest.Name must be defined"}
110106
}
111107

112108
if manifest.OrgName == "" || manifest.SpaceName == "" {
113-
return nil, CloudGovClientError{"ServicePush: AppManifest must have Org and Space names"}
114-
}
115-
116-
// check for an old instance of the service, delete if found
117-
app, err := c.AppGet(containerID)
118-
if err != nil {
119-
var cferr resource.CloudFoundryError
120-
if errors.As(err, &cferr) {
121-
err = nil
122-
if cferr.Code != 10010 {
123-
return nil, fmt.Errorf("unexpected cferr checking for existing app: %w", cferr)
124-
}
125-
} else {
126-
return nil, fmt.Errorf("error checking for existing service (%v): %w", containerID, err)
127-
}
128-
}
129-
if app != nil {
130-
if err := c.AppDelete(containerID); err != nil {
131-
return nil, fmt.Errorf("error deleting existing service (%v): %w", containerID, err)
132-
}
109+
return nil, CloudGovClientError{"Push: AppManifest must have Org and Space names"}
133110
}
134111

135112
return c.appPush(manifest)
@@ -144,7 +121,7 @@ func (c *Client) ServicesPush(manifests []*AppManifest) ([]*App, error) {
144121
apps := make([]*App, len(manifests))
145122

146123
for i, s := range manifests {
147-
app, err := c.ServicePush(s)
124+
app, err := c.Push(s)
148125
if err != nil {
149126
return nil, err
150127
}
@@ -153,3 +130,11 @@ func (c *Client) ServicesPush(manifests []*AppManifest) ([]*App, error) {
153130

154131
return apps, nil
155132
}
133+
134+
func (c *Client) SSHCode() (string, error) {
135+
return c.sshCode()
136+
}
137+
138+
func (c *Client) MapServiceRoute(app *App) error {
139+
return c.mapRoute(context.Background(), app, internalDomainGUID, app.SpaceGUID, app.Name, "", 0)
140+
}

0 commit comments

Comments
 (0)