Skip to content

Commit 8aabaf5

Browse files
committed
feat: collector
1 parent a417b1d commit 8aabaf5

File tree

89 files changed

+4653
-2
lines changed

Some content is hidden

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

89 files changed

+4653
-2
lines changed

cmd/collect_environment.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
8+
"github.com/spf13/cobra"
9+
"github.com/uselagoon/build-deploy-tool/internal/collector"
10+
"github.com/uselagoon/build-deploy-tool/internal/helpers"
11+
"github.com/uselagoon/build-deploy-tool/internal/k8s"
12+
)
13+
14+
func init() {
15+
collectCmd.AddCommand(collectEnvironment)
16+
}
17+
18+
var collectEnvironment = &cobra.Command{
19+
Use: "environment",
20+
Aliases: []string{"e"},
21+
Short: "Collect seed information about the environment",
22+
RunE: func(cmd *cobra.Command, args []string) error {
23+
// get a k8s client
24+
client, err := k8s.NewClient()
25+
if err != nil {
26+
return err
27+
}
28+
// create a collector
29+
col := collector.NewCollector(client)
30+
namespace := helpers.GetEnv("NAMESPACE", "", false)
31+
namespace, err = helpers.GetNamespace(namespace, "/var/run/secrets/kubernetes.io/serviceaccount/namespace")
32+
if err != nil {
33+
return err
34+
}
35+
if namespace == "" {
36+
return fmt.Errorf("unable to detect namespace")
37+
}
38+
// collect the environment
39+
data, err := CollectEnvironment(col, namespace)
40+
if err != nil {
41+
return err
42+
}
43+
env, err := json.MarshalIndent(data, "", " ")
44+
if err != nil {
45+
return err
46+
}
47+
fmt.Println(string(env))
48+
return nil
49+
},
50+
}
51+
52+
// CollectEnvironment .
53+
func CollectEnvironment(c *collector.Collector, namespace string) (*collector.LagoonEnvState, error) {
54+
state, err := c.Collect(context.Background(), namespace)
55+
if err != nil {
56+
return nil, err
57+
}
58+
return state, nil
59+
}

cmd/collect_environment_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"reflect"
7+
"testing"
8+
9+
"github.com/andreyvit/diff"
10+
"github.com/uselagoon/build-deploy-tool/internal/collector"
11+
"github.com/uselagoon/build-deploy-tool/internal/k8s"
12+
13+
// changes the testing to source from root so paths to test resources must be defined from repo root
14+
_ "github.com/uselagoon/build-deploy-tool/internal/testing"
15+
)
16+
17+
func TestCollectEnvironment(t *testing.T) {
18+
type args struct {
19+
namespace string
20+
}
21+
tests := []struct {
22+
name string
23+
args args
24+
seedDir string
25+
want string
26+
wantErr bool
27+
}{
28+
29+
{
30+
name: "list-environment",
31+
args: args{
32+
namespace: "example-project-main",
33+
},
34+
seedDir: "internal/collector/testdata/seed/seed-1",
35+
want: "internal/collector/testdata/json-result/result-1.json",
36+
wantErr: false,
37+
},
38+
39+
{
40+
name: "list-environment-with-pvcs",
41+
args: args{
42+
namespace: "example-project-main",
43+
},
44+
seedDir: "internal/collector/testdata/seed/seed-2",
45+
want: "internal/collector/testdata/json-result/result-2.json",
46+
wantErr: false,
47+
},
48+
}
49+
for _, tt := range tests {
50+
t.Run(tt.name, func(t *testing.T) {
51+
client, err := k8s.NewFakeClient(tt.args.namespace)
52+
if err != nil {
53+
t.Errorf("error creating fake client")
54+
}
55+
err = k8s.SeedFakeData(client, tt.args.namespace, tt.seedDir)
56+
if err != nil {
57+
t.Errorf("error seeding fake data: %v", err)
58+
}
59+
col := collector.NewCollector(client)
60+
got, err := CollectEnvironment(col, tt.args.namespace)
61+
if (err != nil) != tt.wantErr {
62+
t.Errorf("CollectEnvironment() error = %v, wantErr %v", err, tt.wantErr)
63+
return
64+
}
65+
results, err := os.ReadFile(tt.want)
66+
if err != nil {
67+
t.Errorf("couldn't read file %v: %v", tt.want, err)
68+
}
69+
env, err := json.MarshalIndent(got, "", " ")
70+
if err != nil {
71+
t.Errorf("couldn't read file %v: %v", tt.want, err)
72+
}
73+
if !reflect.DeepEqual(string(results), string(env)) {
74+
t.Errorf("Collect() = \n%v", diff.LineDiff(string(env), string(results)))
75+
}
76+
})
77+
}
78+
}

cmd/root.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ var validateCmd = &cobra.Command{
6060
Long: `Validate resources for Lagoon builds`,
6161
}
6262

63+
var collectCmd = &cobra.Command{
64+
Use: "collect",
65+
Aliases: []string{"col", "c"},
66+
Short: "Collect resource information",
67+
Long: `Collect resource information for Lagoon builds`,
68+
}
69+
6370
// Execute adds all child commands to the root command and sets flags appropriately.
6471
// This is called by main.main(). It only needs to happen once to the rootCmd.
6572
func Execute() {
@@ -99,6 +106,7 @@ func init() {
99106
rootCmd.AddCommand(taskCmd)
100107
rootCmd.AddCommand(identifyCmd)
101108
rootCmd.AddCommand(validateCmd)
109+
rootCmd.AddCommand(collectCmd)
102110

103111
rootCmd.PersistentFlags().StringP("lagoon-yml", "l", ".lagoon.yml",
104112
"The .lagoon.yml file to read")

cmd/validate_lagoonyml_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func TestValidateLagoonYml(t *testing.T) {
171171

172172
err = yaml.Unmarshal(wantsLYAMLString, wantsLYAML)
173173
if err != nil {
174-
t.Errorf(err.Error())
174+
t.Errorf("couldn't unmarshal yaml: %v", err)
175175
return
176176
}
177177

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ require (
2727
k8s.io/api v0.32.1
2828
k8s.io/apimachinery v0.32.1
2929
k8s.io/client-go v0.32.1
30+
sigs.k8s.io/controller-runtime v0.20.0
3031
sigs.k8s.io/yaml v1.4.0
3132
)
3233

@@ -86,7 +87,6 @@ require (
8687
k8s.io/klog/v2 v2.130.1 // indirect
8788
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
8889
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
89-
sigs.k8s.io/controller-runtime v0.20.0 // indirect
9090
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
9191
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
9292
)

internal/collector/collector.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package collector
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"strings"
8+
9+
k8upv1 "github.com/k8up-io/k8up/v2/api/v1"
10+
k8upv1alpha1 "github.com/vshn/k8up/api/v1alpha1"
11+
appsv1 "k8s.io/api/apps/v1"
12+
batchv1 "k8s.io/api/batch/v1"
13+
corev1 "k8s.io/api/core/v1"
14+
networkv1 "k8s.io/api/networking/v1"
15+
16+
mariadbv1 "github.com/amazeeio/dbaas-operator/apis/mariadb/v1"
17+
mongodbv1 "github.com/amazeeio/dbaas-operator/apis/mongodb/v1"
18+
postgresv1 "github.com/amazeeio/dbaas-operator/apis/postgres/v1"
19+
client "sigs.k8s.io/controller-runtime/pkg/client"
20+
)
21+
22+
type Collector struct {
23+
Client client.Client
24+
}
25+
26+
type LagoonEnvState struct {
27+
Deployments *appsv1.DeploymentList `json:"deployments"`
28+
Cronjobs *batchv1.CronJobList `json:"cronjobs"`
29+
Ingress *networkv1.IngressList `json:"ingress"`
30+
Services *corev1.ServiceList `json:"services"`
31+
Secrets *corev1.SecretList `json:"secrets"`
32+
PVCs *corev1.PersistentVolumeClaimList `json:"pvcs"`
33+
SchedulesV1 *k8upv1.ScheduleList `json:"schedulesv1"`
34+
SchedulesV1Alpha1 *k8upv1alpha1.ScheduleList `json:"schedulesv1alpha1"`
35+
PreBackupPodsV1 *k8upv1.PreBackupPodList `json:"prebackuppodsv1"`
36+
PreBackupPodsV1Alpha1 *k8upv1alpha1.PreBackupPodList `json:"prebackuppodsv1alpha1"`
37+
MariaDBConsumers *mariadbv1.MariaDBConsumerList `json:"mariadbconsumers"`
38+
MongoDBConsumers *mongodbv1.MongoDBConsumerList `json:"mongodbconsumers"`
39+
PostgreSQLConsumers *postgresv1.PostgreSQLConsumerList `json:"postgresqlconsumers"`
40+
}
41+
42+
func NewCollector(client client.Client) *Collector {
43+
return &Collector{
44+
Client: client,
45+
}
46+
}
47+
48+
func (c *Collector) Collect(ctx context.Context, namespace string) (*LagoonEnvState, error) {
49+
var state LagoonEnvState
50+
var err error
51+
state.Deployments, err = c.CollectDeployments(ctx, namespace)
52+
if err != nil {
53+
return nil, err
54+
}
55+
state.Cronjobs, err = c.CollectCronjobs(ctx, namespace)
56+
if err != nil {
57+
return nil, err
58+
}
59+
state.Ingress, err = c.CollectIngress(ctx, namespace)
60+
if err != nil {
61+
return nil, err
62+
}
63+
state.Services, err = c.CollectServices(ctx, namespace)
64+
if err != nil {
65+
return nil, err
66+
}
67+
state.Secrets, err = c.CollectSecrets(ctx, namespace)
68+
if err != nil {
69+
return nil, err
70+
}
71+
state.PVCs, err = c.CollectPVCs(ctx, namespace)
72+
if err != nil {
73+
return nil, err
74+
}
75+
state.MariaDBConsumers, err = c.CollectMariaDBConsumers(ctx, namespace)
76+
if err != nil {
77+
// handle if consumer crds not installed
78+
if !strings.Contains(err.Error(), "no matches for kind") {
79+
fmt.Fprintln(os.Stderr, err)
80+
return nil, err
81+
}
82+
}
83+
state.MongoDBConsumers, err = c.CollectMongoDBConsumers(ctx, namespace)
84+
if err != nil {
85+
// handle if consumer crds not installed
86+
if !strings.Contains(err.Error(), "no matches for kind") {
87+
fmt.Fprintln(os.Stderr, err)
88+
return nil, err
89+
}
90+
}
91+
state.PostgreSQLConsumers, err = c.CollectPostgreSQLConsumers(ctx, namespace)
92+
if err != nil {
93+
// handle if consumer crds not installed
94+
if !strings.Contains(err.Error(), "no matches for kind") {
95+
fmt.Fprintln(os.Stderr, err)
96+
return nil, err
97+
}
98+
}
99+
state.SchedulesV1, err = c.CollectSchedulesV1(ctx, namespace)
100+
if err != nil {
101+
// handle if k8up v1 crds not installed
102+
if !strings.Contains(err.Error(), "no matches for kind") {
103+
fmt.Fprintln(os.Stderr, err)
104+
return nil, err
105+
}
106+
}
107+
state.SchedulesV1Alpha1, err = c.CollectSchedulesV1Alpha1(ctx, namespace)
108+
if err != nil {
109+
// handle if k8up v1alpha1 crds not installed
110+
if !strings.Contains(err.Error(), "no matches for kind") {
111+
fmt.Fprintln(os.Stderr, err)
112+
return nil, err
113+
}
114+
}
115+
state.PreBackupPodsV1, err = c.CollectPreBackupPodsV1(ctx, namespace)
116+
if err != nil {
117+
// handle if k8up v1 crds not installed
118+
if !strings.Contains(err.Error(), "no matches for kind") {
119+
fmt.Fprintln(os.Stderr, err)
120+
return nil, err
121+
}
122+
}
123+
state.PreBackupPodsV1Alpha1, err = c.CollectPreBackupPodsV1Alpha1(ctx, namespace)
124+
if err != nil {
125+
// handle if k8up v1alpha1 crds not installed
126+
if !strings.Contains(err.Error(), "no matches for kind") {
127+
fmt.Fprintln(os.Stderr, err)
128+
return nil, err
129+
}
130+
}
131+
return &state, nil
132+
}

0 commit comments

Comments
 (0)