Skip to content

Commit f1abd4c

Browse files
authored
Merge pull request #5 from rhd-gitops-example/extract-more-images
Extract images from more resources. * Deployments * StatefulSets * DaemonSets * Jobs * CronJob * DeploymentConfig It also simplifies the approach to extracting the data from the resources.
2 parents 25a9f0c + 425273c commit f1abd4c

21 files changed

+392
-124
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
github.com/mitchellh/mapstructure v1.3.2 // indirect
2222
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect
2323
github.com/onsi/ginkgo v1.12.3 // indirect
24+
github.com/openshift/api v3.9.0+incompatible
2425
github.com/pelletier/go-toml v1.6.0 // indirect
2526
github.com/pkg/errors v0.9.1 // indirect
2627
github.com/prometheus/client_golang v1.1.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
202202
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
203203
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
204204
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
205-
github.com/jenkins-x/go-scm v1.5.142 h1:C3Mu/Heb715Bbptelq7yjx8Ux51Q4slxjLLydE5ogkI=
206-
github.com/jenkins-x/go-scm v1.5.142/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg=
207205
github.com/jenkins-x/go-scm v1.5.151 h1:PrSqpWiRftYXiUniE5XyI1E+4WJMNlyR083q9mBNVTI=
208206
github.com/jenkins-x/go-scm v1.5.151/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg=
209207
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@@ -285,6 +283,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
285283
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
286284
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
287285
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
286+
github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs=
287+
github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
288288
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
289289
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
290290
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=

internal/sets/strings.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package sets
2+
3+
import "sort"
4+
5+
// StringSet is a set of strings with simple functionality for getting a sorted
6+
// set of elements.
7+
type StringSet map[string]bool
8+
9+
// NewStringSet creates a new empty StringSet.
10+
func NewStringSet() StringSet {
11+
return StringSet{}
12+
}
13+
14+
// Add adds a string to the set.
15+
func (s StringSet) Add(n string) {
16+
s[n] = true
17+
}
18+
19+
// Elements returns a sorted list of elements in the set.
20+
func (s StringSet) Elements() []string {
21+
e := []string{}
22+
for k := range s {
23+
e = append(e, k)
24+
}
25+
sort.Strings(e)
26+
return e
27+
}

internal/sets/strings_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package sets
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/go-cmp/cmp"
7+
)
8+
9+
func TestStringSet(t *testing.T) {
10+
s := NewStringSet()
11+
12+
s.Add("test2")
13+
s.Add("test3")
14+
s.Add("test1")
15+
s.Add("test1")
16+
17+
want := []string{"test1", "test2", "test3"}
18+
19+
if diff := cmp.Diff(want, s.Elements()); diff != "" {
20+
t.Fatalf("StringSet failed:\n%s", diff)
21+
}
22+
}

pkg/gitfs/gitfs_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import (
44
"io/ioutil"
55
"testing"
66

7-
"github.com/go-git/go-git/v5"
87
"github.com/google/go-cmp/cmp"
98
"sigs.k8s.io/kustomize/pkg/fs"
9+
10+
"github.com/rhd-gitops-example/gitops-backend/test"
1011
)
1112

1213
var _ fs.FileSystem = gitFS{}
@@ -105,9 +106,7 @@ func TestNewInMemoryFromOptions(t *testing.T) {
105106
func makeClonedGFS(t *testing.T) fs.FileSystem {
106107
t.Helper()
107108
gfs, err := NewInMemoryFromOptions(
108-
&git.CloneOptions{
109-
URL: "../../",
110-
})
109+
test.MakeCloneOptions())
111110
assertNoError(t, err)
112111
return gfs
113112
}

pkg/httpapi/api_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/google/go-cmp/cmp"
1717
"github.com/rhd-gitops-example/gitops-backend/pkg/git"
1818
"github.com/rhd-gitops-example/gitops-backend/pkg/parser"
19-
"github.com/rhd-gitops-example/gitops-backend/pkg/resource"
2019
"github.com/rhd-gitops-example/gitops-backend/test"
2120
"k8s.io/apimachinery/pkg/types"
2221
"sigs.k8s.io/yaml"
@@ -160,7 +159,7 @@ func TestGetPipelinesWithUnknownSecret(t *testing.T) {
160159
}
161160

162161
func TestGetPipelineApplication(t *testing.T) {
163-
testResource := &resource.Resource{
162+
testResource := &parser.Resource{
164163
Group: "",
165164
Version: "v1",
166165
Kind: "Deployment",
@@ -211,7 +210,7 @@ func TestGetPipelineApplication(t *testing.T) {
211210
}
212211

213212
func TestGetPipelineApplicationWithRef(t *testing.T) {
214-
testResource := &resource.Resource{
213+
testResource := &parser.Resource{
215214
Group: "",
216215
Version: "v1",
217216
Kind: "Deployment",
@@ -426,8 +425,8 @@ func (s stubClientFactory) Create(url, token string) (git.SCM, error) {
426425
return s.client, nil
427426
}
428427

429-
func stubResourceParser(r ...*resource.Resource) parser.ResourceParser {
430-
return func(path string, opts *gogit.CloneOptions) ([]*resource.Resource, error) {
428+
func stubResourceParser(r ...*parser.Resource) parser.ResourceParser {
429+
return func(path string, opts *gogit.CloneOptions) ([]*parser.Resource, error) {
431430
return r, nil
432431
}
433432
}

pkg/httpapi/application.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88

99
"github.com/go-git/go-git/v5"
1010
"github.com/go-git/go-git/v5/plumbing/transport/http"
11-
"github.com/rhd-gitops-example/gitops-backend/pkg/resource"
11+
"github.com/rhd-gitops-example/gitops-backend/pkg/parser"
1212
)
1313

14+
const nameLabel = "app.kubernetes.io/name"
15+
1416
// TODO: if the environment doesn't exist, this should return a not found error.
1517
func (a *APIRouter) environmentApplication(authToken string, c *config, envName, appName string) (map[string]interface{}, error) {
1618
if c.GitOpsURL == "" {
@@ -47,9 +49,9 @@ func pathForApplication(appName, envName string) string {
4749
return path.Join("environments", envName, "apps", appName)
4850
}
4951

50-
func parseServicesFromResources(env *environment, res []*resource.Resource) ([]responseService, error) {
52+
func parseServicesFromResources(env *environment, res []*parser.Resource) ([]responseService, error) {
5153
serviceImages := map[string]map[string]bool{}
52-
serviceResources := map[string][]*resource.Resource{}
54+
serviceResources := map[string][]*parser.Resource{}
5355
for _, v := range res {
5456
name := serviceFromLabels(v.Labels)
5557
images, ok := serviceImages[name]
@@ -62,7 +64,7 @@ func parseServicesFromResources(env *environment, res []*resource.Resource) ([]r
6264
serviceImages[name] = images
6365
resources, ok := serviceResources[name]
6466
if !ok {
65-
resources = []*resource.Resource{}
67+
resources = []*parser.Resource{}
6668
}
6769
resources = append(resources, v)
6870
serviceResources[name] = resources
@@ -92,17 +94,15 @@ func parseServicesFromResources(env *environment, res []*resource.Resource) ([]r
9294
return services, nil
9395
}
9496

95-
const nameLabel = "app.kubernetes.io/name"
96-
9797
func serviceFromLabels(l map[string]string) string {
9898
return l[nameLabel]
9999
}
100100

101101
type responseService struct {
102-
Name string `json:"name"`
103-
Source source `json:"source,omitempty"`
104-
Images []string `json:"images,omitempty"`
105-
Resources []*resource.Resource `json:"resources,omitempty"`
102+
Name string `json:"name"`
103+
Source source `json:"source,omitempty"`
104+
Images []string `json:"images,omitempty"`
105+
Resources []*parser.Resource `json:"resources,omitempty"`
106106
}
107107

108108
type source struct {

pkg/httpapi/application_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
"github.com/google/go-cmp/cmp"
8-
"github.com/rhd-gitops-example/gitops-backend/pkg/resource"
8+
"github.com/rhd-gitops-example/gitops-backend/pkg/parser"
99
)
1010

1111
const (
@@ -15,7 +15,7 @@ const (
1515
const testSourceURL = "https://github.com/rhd-example-gitops/gitops-demo.git"
1616

1717
func TestParseServicesFromResources(t *testing.T) {
18-
goDemoResources := []*resource.Resource{
18+
goDemoResources := []*parser.Resource{
1919
{
2020
Group: "apps", Version: "v1", Kind: "Deployment", Name: "go-demo-http",
2121
Labels: map[string]string{
@@ -40,7 +40,7 @@ func TestParseServicesFromResources(t *testing.T) {
4040
},
4141
}
4242

43-
redisResources := []*resource.Resource{
43+
redisResources := []*parser.Resource{
4444
{
4545
Version: "v1", Kind: "Service", Name: "redis",
4646
Labels: map[string]string{
@@ -109,7 +109,7 @@ func TestParseServicesFromResources(t *testing.T) {
109109
}
110110

111111
func TestParseServicesFromResourcesReturnsSetOfImages(t *testing.T) {
112-
res := []*resource.Resource{
112+
res := []*parser.Resource{
113113
{
114114
Group: "apps", Version: "v1", Kind: "Deployment", Name: "go-demo-http",
115115
Labels: map[string]string{

pkg/parser/converter.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package parser
2+
3+
import (
4+
ocpappsv1 "github.com/openshift/api/apps/v1"
5+
appsv1 "k8s.io/api/apps/v1"
6+
batchv1 "k8s.io/api/batch/v1"
7+
batchv1beta1 "k8s.io/api/batch/v1beta1"
8+
corev1 "k8s.io/api/core/v1"
9+
10+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
11+
"k8s.io/apimachinery/pkg/runtime"
12+
)
13+
14+
// unstructuredConverter handles conversions between unstructured.Unstructured
15+
// and some core Kubernetes resource types.
16+
type unstructuredConverter struct {
17+
scheme *runtime.Scheme
18+
}
19+
20+
// newUnstructuredConverter creates and returns a new UnstructuredConverter.
21+
func newUnstructuredConverter() (*unstructuredConverter, error) {
22+
schemeBuilder := runtime.SchemeBuilder{
23+
corev1.AddToScheme,
24+
appsv1.AddToScheme,
25+
batchv1.AddToScheme,
26+
batchv1beta1.AddToScheme,
27+
ocpappsv1.AddToScheme,
28+
}
29+
30+
uc := &unstructuredConverter{
31+
scheme: runtime.NewScheme(),
32+
}
33+
34+
if err := schemeBuilder.AddToScheme(uc.scheme); err != nil {
35+
return nil, err
36+
}
37+
return uc, nil
38+
}
39+
40+
// fromUnstructured converts an unstructured.Unstructured to typed struct.
41+
//
42+
// If unable to convert using the Kind of obj, then an error is returned.
43+
func (c *unstructuredConverter) fromUnstructured(o *unstructured.Unstructured) (interface{}, error) {
44+
newObj, err := c.scheme.New(o.GetObjectKind().GroupVersionKind())
45+
if err != nil {
46+
return nil, err
47+
}
48+
return newObj, c.scheme.Convert(o, newObj, nil)
49+
}

pkg/parser/extracts.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package parser
2+
3+
import (
4+
ocpappsv1 "github.com/openshift/api/apps/v1"
5+
appsv1 "k8s.io/api/apps/v1"
6+
batchv1 "k8s.io/api/batch/v1"
7+
batchv1beta1 "k8s.io/api/batch/v1beta1"
8+
corev1 "k8s.io/api/core/v1"
9+
10+
"github.com/rhd-gitops-example/gitops-backend/internal/sets"
11+
)
12+
13+
// Deployments, DeploymentConfigs, StatefulSets, DaemonSets, Jobs, CronJobs
14+
func extractImages(v interface{}) []string {
15+
switch k := v.(type) {
16+
case *appsv1.Deployment:
17+
return extractImagesFromPodTemplateSpec(k.Spec.Template)
18+
case *appsv1.StatefulSet:
19+
return extractImagesFromPodTemplateSpec(k.Spec.Template)
20+
case *appsv1.DaemonSet:
21+
return extractImagesFromPodTemplateSpec(k.Spec.Template)
22+
case *batchv1.Job:
23+
return extractImagesFromPodTemplateSpec(k.Spec.Template)
24+
case *batchv1beta1.CronJob:
25+
return extractImagesFromPodTemplateSpec(k.Spec.JobTemplate.Spec.Template)
26+
case *ocpappsv1.DeploymentConfig:
27+
return extractImagesFromPodTemplateSpec(*k.Spec.Template)
28+
}
29+
return nil
30+
}
31+
32+
func extractImagesFromPodTemplateSpec(p corev1.PodTemplateSpec) []string {
33+
images := sets.NewStringSet()
34+
for _, c := range p.Spec.InitContainers {
35+
images.Add(c.Image)
36+
}
37+
for _, c := range p.Spec.Containers {
38+
images.Add(c.Image)
39+
}
40+
return images.Elements()
41+
}

0 commit comments

Comments
 (0)