Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reaper: Add support for google source repository #45

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion tools/reaper/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"strings"
"time"

"github.com/fluxcd/test-infra/tftestenv"
)
Expand All @@ -35,6 +36,22 @@ func queryGCP(binPath, jqPath, project, labelKey, labelVal string) string {
binPath, jqPath, project, labelKey, labelVal)
}

// queryGCPSourceRepos returns a GCP command for querying all the source
// repositories in a specific format compatible with the resource type.
func queryGCPSourceRepos(binPath, jqPath, project string) string {
// TODO: Figure out a better way to detect the age of the repository.
// Currently, all the repositories are deleted with fixed now-1hr createdat
// time.
now := time.Now().UTC()
createdat := now.Add(-time.Hour)
tagVal := createdat.Format(tftestenv.CreatedAtTimeLayout)
return fmt.Sprintf(`%[1]s source repos list --project %[3]s --format=json |
%[2]s '.[] |
{name, "type": "cloud-source-repository", "tags": { "createdat": "%[4]s" }}' |
%[2]s -s '.'`,
binPath, jqPath, project, tagVal)
}

// deleteGCPArtifactRepositoryCmd returns a gcloud command for deleting a Google
// Artifact Repository instance.
func deleteGCPArtifactRepositoryCmd(binPath, project, name, location string) string {
Expand All @@ -48,16 +65,47 @@ func deleteGCPClusterCmd(binPath, project, name, location string) string {
binPath, project, name, location)
}

// deleteGCPSourceRepoCmd returns a gcloud command for deleting cloud source
// repository.
func deleteGCPSourceRepoCmd(binPath, project, name string) string {
return fmt.Sprintf(`%[1]s source repos delete %[3]s --project %[2]s --quiet`,
binPath, project, name)
}

func getGCPSourceRepos(ctx context.Context, cliPath, jqPath string) ([]resource, error) {
output, err := tftestenv.RunCommandWithOutput(ctx, "./",
queryGCPSourceRepos(cliPath, jqPath, *gcpProject),
tftestenv.RunCommandOptions{},
)
if err != nil {
return nil, err
}
return parseJSONResources(output)
}

// getGCPResources queries GCP for resources.
func getGCPResources(ctx context.Context, cliPath, jqPath string) ([]resource, error) {
result := []resource{}
output, err := tftestenv.RunCommandWithOutput(ctx, "./",
queryGCP(cliPath, jqPath, *gcpProject, tagKey, tagVal),
tftestenv.RunCommandOptions{},
)
if err != nil {
return nil, err
}
return parseJSONResources(output)
r, err := parseJSONResources(output)
if err != nil {
return nil, err
}
result = append(result, r...)

sr, err := getGCPSourceRepos(ctx, cliPath, jqPath)
if err != nil {
return nil, err
}
result = append(result, sr...)

return result, nil
}

// getGCPDefaultProject queries for the gcloud default/current project.
Expand Down Expand Up @@ -94,3 +142,12 @@ func deleteGCPArtifactRepository(ctx context.Context, cliPath string, res resour
)
return err
}

// deleteGCPSourceRepo deletes a Google cloud source repository.
func deleteGCPSourceRepo(ctx context.Context, cliPath string, res resource) error {
_, err := tftestenv.RunCommandWithOutput(ctx, "./",
deleteGCPSourceRepoCmd(cliPath, *gcpProject, res.Name),
tftestenv.RunCommandOptions{AttachConsole: true},
)
return err
}
26 changes: 26 additions & 0 deletions tools/reaper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ var clusterTypes map[string]string = map[string]string{
gcp: "container.googleapis.com/Cluster",
}

// sourceRepoTypes maps the source repository type resource with their
// resource.Type value in different providers. This is used to identify that a
// given resource is a source repository in a particular provider.
var sourceRepoTypes map[string]string = map[string]string{
aws: "",
azure: "",
gcp: "cloud-source-repository",
}

// resource is a common representation of a cloud resource with the minimal
// attributes needed to uniquely identify them.
type resource struct {
Expand Down Expand Up @@ -246,6 +255,13 @@ func main() {
log.Fatalf("Failed to delete cluster: %v", err)
}
}

srcRepos := getSourceRepos(*targetProvider, resources)
for _, repo := range srcRepos {
if err := deleteGCPSourceRepo(ctx, gcloudPath, repo); err != nil {
log.Fatalf("Failed to delete source repository: %v", err)
}
}
case awsnuke:
if err := awsNuker.Delete(ctx); err != nil {
log.Fatalf("Failed to delete resources: %v", err)
Expand Down Expand Up @@ -279,6 +295,16 @@ func getClusters(provider string, resources []resource) []resource {
return result
}

func getSourceRepos(provider string, resources []resource) []resource {
result := []resource{}
for _, r := range resources {
if r.Type == sourceRepoTypes[provider] {
result = append(result, r)
}
}
return result
}

func getAzureResourceGroups(resources []resource) []resource {
result := []resource{}
for _, r := range resources {
Expand Down
15 changes: 15 additions & 0 deletions tools/reaper/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,21 @@ func TestParseJSONResources(t *testing.T) {
"type": "Microsoft.Resources/resourceGroups"
}
]
`),
wantItems: 1,
},
{
name: "GCP source repository",
data: []byte(`
[
{
"name": "projects/cncf-flux/repos/fleet-infra-sure-marmot",
"type": "cloud-source-repository",
"tags": {
"createdat": "aaaa"
}
}
]
`),
wantItems: 1,
},
Expand Down