forked from knative/func
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.go
More file actions
169 lines (146 loc) · 6.32 KB
/
client.go
File metadata and controls
169 lines (146 loc) · 6.32 KB
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
162
163
164
165
166
167
168
169
package cmd
import (
"fmt"
"net/http"
"os"
"knative.dev/func/cmd/prompt"
"knative.dev/func/pkg/builders/buildpacks"
"knative.dev/func/pkg/config"
"knative.dev/func/pkg/creds"
"knative.dev/func/pkg/docker"
fn "knative.dev/func/pkg/functions"
fnhttp "knative.dev/func/pkg/http"
"knative.dev/func/pkg/k8s"
"knative.dev/func/pkg/knative"
"knative.dev/func/pkg/oci"
"knative.dev/func/pkg/pipelines/tekton"
)
// ClientConfig settings for use with NewClient
// These are the minimum settings necessary to create the default client
// instance which has most subsystems initialized.
type ClientConfig struct {
// Verbose logging. By default, logging output is kept to the bare minimum.
// Use this flag to configure verbose logging throughout.
Verbose bool
// Allow insecure server connections when using SSL
InsecureSkipVerify bool
}
// ClientFactory defines a constructor which assists in the creation of a Client
// for use by commands.
// See the NewClient constructor which is the fully populated ClientFactory used
// by commands by default.
// See NewClientFactory which constructs a minimal ClientFactory for use
// during testing.
type ClientFactory func(ClientConfig, ...fn.Option) (*fn.Client, func())
// NewTestClient returns a client factory which will ignore options used,
// instead using those provided when creating the factory. This allows
// for tests to create an entirely default client but with N mocks.
func NewTestClient(options ...fn.Option) ClientFactory {
return func(_ ClientConfig, _ ...fn.Option) (*fn.Client, func()) {
return fn.New(options...), func() {}
}
}
// NewClient constructs an fn.Client with the majority of
// the concrete implementations set. Provide additional Options to this constructor
// to override or augment as needed, or override the ClientFactory passed to
// commands entirely to mock for testing. Note the returned cleanup function.
// 'Namespace' is optional. If not provided (see DefaultNamespace commentary),
// the currently configured is used.
// 'Verbose' indicates the system should write out a higher amount of logging.
func NewClient(cfg ClientConfig, options ...fn.Option) (*fn.Client, func()) {
var (
t = newTransport(cfg.InsecureSkipVerify) // may provide a custom impl which proxies
c = newCredentialsProvider(config.Dir(), t, "") // for accessing registries
d = newKnativeDeployer(cfg.Verbose) // default deployer (can be overridden via options)
pp = newTektonPipelinesProvider(c, cfg.Verbose)
o = []fn.Option{ // standard (shared) options for all commands
fn.WithVerbose(cfg.Verbose),
fn.WithTransport(t),
fn.WithRepositoriesPath(config.RepositoriesPath()),
fn.WithBuilder(buildpacks.NewBuilder(buildpacks.WithVerbose(cfg.Verbose))),
fn.WithRemovers(knative.NewRemover(cfg.Verbose), k8s.NewRemover(cfg.Verbose)),
fn.WithDescribers(knative.NewDescriber(cfg.Verbose), k8s.NewDescriber(cfg.Verbose)),
fn.WithListers(knative.NewLister(cfg.Verbose), k8s.NewLister(cfg.Verbose)),
fn.WithDeployer(d),
fn.WithPipelinesProvider(pp),
fn.WithPusher(docker.NewPusher(
docker.WithCredentialsProvider(c),
docker.WithTransport(t),
docker.WithVerbose(cfg.Verbose))),
}
)
// Client is constructed with standard options plus any additional options
// which either augment or override the defaults.
client := fn.New(append(o, options...)...)
// A deferrable cleanup function which is used to perform any cleanup, such
// as closing the transport
cleanup := func() {
if err := t.Close(); err != nil {
fmt.Fprintf(os.Stderr, "error closing http transport. %v", err)
}
}
return client, cleanup
}
// newTransport returns a transport with cluster-flavor-specific variations
// which take advantage of additional features offered by cluster variants.
func newTransport(insecureSkipVerify bool) fnhttp.RoundTripCloser {
return fnhttp.NewRoundTripper(fnhttp.WithInsecureSkipVerify(insecureSkipVerify), fnhttp.WithOpenShiftServiceCA())
}
// newCredentialsProvider returns a credentials provider which possibly
// has cluster-flavor specific additional credential loaders to take advantage
// of features or configuration nuances of cluster variants.
// If authFilePath is provided (non-empty), it will be used as the primary auth file.
func newCredentialsProvider(configPath string, t http.RoundTripper, authFilePath string) oci.CredentialsProvider {
additionalLoaders := append(k8s.GetOpenShiftDockerCredentialLoaders(), k8s.GetGoogleCredentialLoader()...)
additionalLoaders = append(additionalLoaders, k8s.GetECRCredentialLoader()...)
additionalLoaders = append(additionalLoaders, k8s.GetACRCredentialLoader()...)
options := []creds.Opt{
creds.WithPromptForCredentials(prompt.NewPromptForCredentials(os.Stdin, os.Stdout, os.Stderr)),
creds.WithPromptForCredentialStore(prompt.NewPromptForCredentialStore()),
creds.WithTransport(t),
creds.WithAdditionalCredentialLoaders(additionalLoaders...),
}
// If a custom auth file path is provided, use it
if authFilePath != "" {
options = append(options, creds.WithAuthFilePath(authFilePath))
}
// Other cluster variants can be supported here
return creds.NewCredentialsProvider(configPath, options...)
}
func newTektonPipelinesProvider(creds oci.CredentialsProvider, verbose bool) *tekton.PipelinesProvider {
options := []tekton.Opt{
tekton.WithCredentialsProvider(creds),
tekton.WithVerbose(verbose),
tekton.WithPipelineDecorator(deployDecorator{}),
}
return tekton.NewPipelinesProvider(options...)
}
func newKnativeDeployer(verbose bool) fn.Deployer {
options := []knative.DeployerOpt{
knative.WithDeployerVerbose(verbose),
knative.WithDeployerDecorator(deployDecorator{}),
}
return knative.NewDeployer(options...)
}
func newK8sDeployer(verbose bool) fn.Deployer {
options := []k8s.DeployerOpt{
k8s.WithDeployerVerbose(verbose),
k8s.WithDeployerDecorator(deployDecorator{}),
}
return k8s.NewDeployer(options...)
}
type deployDecorator struct {
oshDec k8s.OpenshiftMetadataDecorator
}
func (d deployDecorator) UpdateAnnotations(function fn.Function, annotations map[string]string) map[string]string {
if k8s.IsOpenShift() {
return d.oshDec.UpdateAnnotations(function, annotations)
}
return annotations
}
func (d deployDecorator) UpdateLabels(function fn.Function, labels map[string]string) map[string]string {
if k8s.IsOpenShift() {
return d.oshDec.UpdateLabels(function, labels)
}
return labels
}