-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
discovery.go
161 lines (142 loc) · 5.13 KB
/
discovery.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package discovery
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
log "github.com/sirupsen/logrus"
pluginclient "github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/cmp"
"github.com/argoproj/argo-cd/v2/util/io"
"github.com/argoproj/argo-cd/v2/util/kustomize"
)
func IsManifestGenerationEnabled(sourceType v1alpha1.ApplicationSourceType, enableGenerateManifests map[string]bool) bool {
if enableGenerateManifests == nil {
return true
}
enabled, ok := enableGenerateManifests[string(sourceType)]
if !ok {
return true
}
return enabled
}
func Discover(ctx context.Context, repoPath string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string) (map[string]string, error) {
apps := make(map[string]string)
// Check if it is CMP
conn, _, err := DetectConfigManagementPlugin(ctx, repoPath, []string{}, tarExcludedGlobs)
if err == nil {
// Found CMP
io.Close(conn)
apps["."] = string(v1alpha1.ApplicationSourceTypePlugin)
return apps, nil
}
err = filepath.Walk(repoPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
dir, err := filepath.Rel(repoPath, filepath.Dir(path))
if err != nil {
return err
}
base := filepath.Base(path)
if strings.HasSuffix(base, "Chart.yaml") && IsManifestGenerationEnabled(v1alpha1.ApplicationSourceTypeHelm, enableGenerateManifests) {
apps[dir] = string(v1alpha1.ApplicationSourceTypeHelm)
}
if kustomize.IsKustomization(base) && IsManifestGenerationEnabled(v1alpha1.ApplicationSourceTypeKustomize, enableGenerateManifests) {
apps[dir] = string(v1alpha1.ApplicationSourceTypeKustomize)
}
return nil
})
return apps, err
}
func AppType(ctx context.Context, path string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string) (string, error) {
apps, err := Discover(ctx, path, enableGenerateManifests, tarExcludedGlobs)
if err != nil {
return "", err
}
appType, ok := apps["."]
if ok {
return appType, nil
}
return "Directory", nil
}
// 1. list all plugins in /plugins folder
// 2. foreach plugin setup connection with respective cmp-server
// 3. check isSupported(path)?
// 4.a if no then close connection
// 4.b if yes then return conn for detected plugin
func DetectConfigManagementPlugin(ctx context.Context, repoPath string, env []string, tarExcludedGlobs []string) (io.Closer, pluginclient.ConfigManagementPluginServiceClient, error) {
var conn io.Closer
var cmpClient pluginclient.ConfigManagementPluginServiceClient
pluginSockFilePath := common.GetPluginSockFilePath()
log.WithFields(log.Fields{
common.SecurityField: common.SecurityLow,
common.SecurityCWEField: 775,
}).Debugf("pluginSockFilePath is: %s", pluginSockFilePath)
files, err := os.ReadDir(pluginSockFilePath)
if err != nil {
return nil, nil, err
}
var connFound bool
for _, file := range files {
if file.Type() == os.ModeSocket {
address := filepath.Join(pluginSockFilePath, file.Name())
cmpclientset := pluginclient.NewConfigManagementPluginClientSet(address)
conn, cmpClient, err = cmpclientset.NewConfigManagementPluginClient()
if err != nil {
log.WithFields(log.Fields{
common.SecurityField: common.SecurityMedium,
common.SecurityCWEField: 775,
}).Errorf("error dialing to cmp-server for plugin %s, %v", file.Name(), err)
continue
}
isSupported, err := matchRepositoryCMP(ctx, repoPath, cmpClient, env, tarExcludedGlobs)
if err != nil {
log.WithFields(log.Fields{
common.SecurityField: common.SecurityMedium,
common.SecurityCWEField: 775,
}).Errorf("repository %s is not the match because %v", repoPath, err)
continue
}
if !isSupported {
log.WithFields(log.Fields{
common.SecurityField: common.SecurityLow,
common.SecurityCWEField: 775,
}).Debugf("Reponse from socket file %s is not supported", file.Name())
io.Close(conn)
} else {
connFound = true
break
}
}
}
if !connFound {
return nil, nil, fmt.Errorf("Couldn't find cmp-server plugin supporting repository %s", repoPath)
}
return conn, cmpClient, err
}
// matchRepositoryCMP will send the repoPath to the cmp-server. The cmp-server will
// inspect the files and return true if the repo is supported for manifest generation.
// Will return false otherwise.
func matchRepositoryCMP(ctx context.Context, repoPath string, client pluginclient.ConfigManagementPluginServiceClient, env []string, tarExcludedGlobs []string) (bool, error) {
matchRepoStream, err := client.MatchRepository(ctx, grpc_retry.Disable())
if err != nil {
return false, fmt.Errorf("error getting stream client: %s", err)
}
err = cmp.SendRepoStream(ctx, repoPath, repoPath, matchRepoStream, env, tarExcludedGlobs)
if err != nil {
return false, fmt.Errorf("error sending stream: %s", err)
}
resp, err := matchRepoStream.CloseAndRecv()
if err != nil {
return false, fmt.Errorf("error receiving stream response: %s", err)
}
return resp.GetIsSupported(), nil
}