Skip to content
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
19 changes: 13 additions & 6 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"knative.dev/func/pkg/config"
"knative.dev/func/pkg/docker"
fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/k8s"
"knative.dev/func/pkg/oci"
"knative.dev/func/pkg/s2i"
)
Expand Down Expand Up @@ -171,8 +172,13 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro

f = cfg.Configure(f) // Returns an f updated with values from the config (flags, envs, etc)

cc, _ := k8s.BuildClientConfig("", "", "", fn.Local{})
kc := k8s.NewClient(cc)

f.Registry = resolveRegistry(f.Registry, "", kc)

// Client
clientOptions, err := cfg.clientOptions()
clientOptions, err := cfg.clientOptions(kc)
if err != nil {
return
}
Expand Down Expand Up @@ -264,8 +270,9 @@ func newBuildConfig() buildConfig {
return buildConfig{
Global: config.Global{
Builder: viper.GetString("builder"),
Cluster: viper.GetString("cluster"),
Confirm: viper.GetBool("confirm"),
Registry: registry(), // deferred defaulting
Registry: viper.GetString("registry"),
Verbose: viper.GetBool("verbose"),
RegistryInsecure: viper.GetBool("registry-insecure"),
},
Expand Down Expand Up @@ -441,22 +448,22 @@ func (c buildConfig) Validate(cmd *cobra.Command) (err error) {
// TODO: As a further optimization, it might be ideal to only build the
// image necessary for the target cluster, since the end product of a function
// deployment is not the container, but rather the running service.
func (c buildConfig) clientOptions() ([]fn.Option, error) {
func (c buildConfig) clientOptions(kc *k8s.Client) ([]fn.Option, error) {
o := []fn.Option{
fn.WithRegistry(c.Registry),
fn.WithRegistryInsecure(c.RegistryInsecure),
}

t := newTransport(c.RegistryInsecure)
creds := newCredentialsProvider(config.Dir(), t, c.RegistryAuthfile, c.RegistryInsecure)
t := newTransport(kc, c.RegistryInsecure)
creds := newCredentialsProvider(kc, config.Dir(), t, c.RegistryAuthfile, c.RegistryInsecure)

switch c.Builder {
case builders.Host:
o = append(o,
fn.WithScaffolder(oci.NewScaffolder(c.Verbose)),
fn.WithBuilder(oci.NewBuilder(builders.Host, c.Verbose)),
fn.WithPusher(oci.NewPusher(c.RegistryInsecure, false, c.Verbose,
oci.WithTransport(newTransport(c.RegistryInsecure)),
oci.WithTransport(newTransport(kc, c.RegistryInsecure)),
oci.WithCredentialsProvider(creds),
oci.WithVerbose(c.Verbose))),
)
Expand Down
84 changes: 55 additions & 29 deletions cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type ClientConfig struct {

// Allow insecure server connections when using SSL
InsecureSkipVerify bool

// Constructed k8s client config to be used with optional overrides
K8sClient *k8s.Client
}

// ClientFactory defines a constructor which assists in the creation of a Client
Expand All @@ -45,6 +48,9 @@ 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.
//
// gauron99: this could take *k8s.Client as parameter for easy testing if eg.
// testing cmd function's full flow with fake openshift cluster is desired
func NewTestClient(options ...fn.Option) ClientFactory {
return func(_ ClientConfig, _ ...fn.Option) (*fn.Client, func()) {
return fn.New(options...), func() {}
Expand All @@ -60,31 +66,32 @@ func NewTestClient(options ...fn.Option) ClientFactory {
// '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, "", cfg.InsecureSkipVerify) // for accessing registries
d = newKnativeDeployer(cfg.Verbose) // default deployer (can be overridden via options)
pp = newTektonPipelinesProvider(c, cfg.Verbose, t)
kc = newK8sClient(cfg.K8sClient)
t = newTransport(kc, cfg.InsecureSkipVerify) // may provide a custom impl which proxies
c = newCredentialsProvider(kc, config.Dir(), t, "", cfg.InsecureSkipVerify) // for accessing registries
d = newKnativeDeployer(kc, cfg.Verbose) // default deployer (can be overridden via options)
pp = newTektonPipelinesProvider(kc, c, cfg.Verbose, t)
o = []fn.Option{ // standard (shared) options for all commands
fn.WithVerbose(cfg.Verbose),
fn.WithTransport(t),
fn.WithRepositoriesPath(config.RepositoriesPath()),
fn.WithScaffolder(buildpacks.NewScaffolder(cfg.Verbose)),
fn.WithBuilder(buildpacks.NewBuilder(buildpacks.WithVerbose(cfg.Verbose))),
fn.WithRemovers(knative.NewRemover(cfg.Verbose), k8s.NewRemover(cfg.Verbose), keda.NewRemover(cfg.Verbose)),
fn.WithRemovers(knative.NewRemover(kc, cfg.Verbose), k8s.NewRemover(kc, cfg.Verbose), keda.NewRemover(kc, cfg.Verbose)),
fn.WithDescribers(
knative.NewDescriber(cfg.Verbose, knative.WithDescriberTransport(t)),
k8s.NewDescriber(cfg.Verbose, k8s.WithDescriberTransport(t)),
keda.NewDescriber(cfg.Verbose, keda.WithDescriberTransport(t)),
knative.NewDescriber(kc, cfg.Verbose, knative.WithDescriberTransport(t)),
k8s.NewDescriber(kc, cfg.Verbose, k8s.WithDescriberTransport(t)),
keda.NewDescriber(kc, cfg.Verbose, keda.WithDescriberTransport(t)),
),
fn.WithListers(knative.NewLister(cfg.Verbose), k8s.NewLister(cfg.Verbose), keda.NewLister(cfg.Verbose)),
fn.WithListers(knative.NewLister(kc, cfg.Verbose), k8s.NewLister(kc, cfg.Verbose), keda.NewLister(kc, cfg.Verbose)),
fn.WithDeployer(d),
fn.WithPipelinesProvider(pp),
fn.WithPusher(docker.NewPusher(
docker.WithCredentialsProvider(c),
docker.WithTransport(t),
docker.WithVerbose(cfg.Verbose),
docker.WithInsecure(cfg.InsecureSkipVerify))),
fn.WithSyncer(operator.NewSyncer(operator.WithCredentialsProvider(c))),
fn.WithSyncer(operator.NewSyncer(kc, operator.WithCredentialsProvider(c))),
}
)

Expand All @@ -103,19 +110,37 @@ func NewClient(cfg ClientConfig, options ...fn.Option) (*fn.Client, func()) {
return client, cleanup
}

// newK8sClient is a convenient method of initializing k8s client
func newK8sClient(in *k8s.Client) *k8s.Client {
if in != nil {
return in
}
cc, _ := k8s.BuildClientConfig("", "", "", fn.Local{})
return k8s.NewClient(cc)
}

// newK8sClientFromConfig builds a *k8s.Client from explicit cluster parameters.
func newK8sClientFromConfig(cluster, token, namespace string, local fn.Local) (*k8s.Client, error) {
cc, err := k8s.BuildClientConfig(cluster, token, namespace, local)
if err != nil {
return nil, err
}
return k8s.NewClient(cc), nil
}

// 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())
func newTransport(kc *k8s.Client, insecureSkipVerify bool) fnhttp.RoundTripCloser {
return fnhttp.NewRoundTripper(kc, fnhttp.WithInsecureSkipVerify(insecureSkipVerify), fnhttp.WithOpenShiftServiceCA(kc))
}

// 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.
// When insecure is true, credential verification uses plain HTTP instead of HTTPS.
func newCredentialsProvider(configPath string, t http.RoundTripper, authFilePath string, insecure bool) oci.CredentialsProvider {
additionalLoaders := append(k8s.GetOpenShiftDockerCredentialLoaders(), k8s.GetGoogleCredentialLoader()...)
func newCredentialsProvider(k8sClient *k8s.Client, configPath string, t http.RoundTripper, authFilePath string, insecure bool) oci.CredentialsProvider {
additionalLoaders := append(k8s.GetOpenShiftDockerCredentialLoaders(k8sClient), k8s.GetGoogleCredentialLoader()...)
additionalLoaders = append(additionalLoaders, k8s.GetECRCredentialLoader()...)
additionalLoaders = append(additionalLoaders, k8s.GetACRCredentialLoader()...)

Expand Down Expand Up @@ -152,57 +177,58 @@ func newCredentialsProvider(configPath string, t http.RoundTripper, authFilePath
return creds.NewCredentialsProvider(configPath, options...)
}

func newTektonPipelinesProvider(creds oci.CredentialsProvider, verbose bool, transport http.RoundTripper) *tekton.PipelinesProvider {
func newTektonPipelinesProvider(kc *k8s.Client, creds oci.CredentialsProvider, verbose bool, transport http.RoundTripper) *tekton.PipelinesProvider {
options := []tekton.Opt{
tekton.WithCredentialsProvider(creds),
tekton.WithVerbose(verbose),
tekton.WithPipelineDecorator(deployDecorator{}),
tekton.WithPipelineDecorator(deployDecorator{k8sClient: kc}),
tekton.WithTransport(transport),
}

return tekton.NewPipelinesProvider(options...)
return tekton.NewPipelinesProvider(kc, options...)
}

func newKnativeDeployer(verbose bool) fn.Deployer {
func newKnativeDeployer(kc *k8s.Client, verbose bool) fn.Deployer {
options := []knative.DeployerOpt{
knative.WithDeployerVerbose(verbose),
knative.WithDeployerDecorator(deployDecorator{}),
knative.WithDeployerDecorator(deployDecorator{k8sClient: kc}),
}

return knative.NewDeployer(options...)
return knative.NewDeployer(kc, options...)
}

func newK8sDeployer(verbose bool) fn.Deployer {
func newK8sDeployer(kc *k8s.Client, verbose bool) fn.Deployer {
options := []k8s.DeployerOpt{
k8s.WithDeployerVerbose(verbose),
k8s.WithDeployerDecorator(deployDecorator{}),
k8s.WithDeployerDecorator(deployDecorator{k8sClient: kc}),
}

return k8s.NewDeployer(options...)
return k8s.NewDeployer(kc, options...)
}

func newKedaDeployer(verbose bool) fn.Deployer {
func newKedaDeployer(kc *k8s.Client, verbose bool) fn.Deployer {
options := []keda.DeployerOpt{
keda.WithDeployerVerbose(verbose),
keda.WithDeployerDecorator(deployDecorator{}),
keda.WithDeployerDecorator(deployDecorator{k8sClient: kc}),
}

return keda.NewDeployer(options...)
return keda.NewDeployer(kc, options...)
}

type deployDecorator struct {
oshDec k8s.OpenshiftMetadataDecorator
k8sClient *k8s.Client
oshDec k8s.OpenshiftMetadataDecorator
}

func (d deployDecorator) UpdateAnnotations(function fn.Function, annotations map[string]string) map[string]string {
if k8s.IsOpenShift() {
if d.k8sClient != nil && d.k8sClient.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() {
if d.k8sClient != nil && d.k8sClient.IsOpenshift() {
return d.oshDec.UpdateLabels(function, labels)
}
return labels
Expand Down
6 changes: 4 additions & 2 deletions cmd/completion_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ import (
)

func CompleteFunctionList(cmd *cobra.Command, args []string, toComplete string) (strings []string, directive cobra.ShellCompDirective) {
cc, _ := k8s.BuildClientConfig("", "", "", fn.Local{})
kc := k8s.NewClient(cc)
listers := []fn.Lister{
knative.NewLister(false),
k8s.NewLister(false),
knative.NewLister(kc, false),
k8s.NewLister(kc, false),
}

items := []fn.ListItem{}
Expand Down
9 changes: 7 additions & 2 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,19 @@ func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
if err != nil {
return
}
// construct k8s client for some commands do cluster search
kc, err := newK8sClientFromConfig(function.Deploy.Cluster, "", function.Deploy.Namespace, function.Local)
if err != nil {
return
}

switch answers.SelectedOperation {
case "Add":
switch answers.SelectedConfig {
case "Volumes":
err = runAddVolumesPrompt(cmd.Context(), function)
err = runAddVolumesPrompt(cmd.Context(), kc, function)
case "Environment variables":
err = runAddEnvsPrompt(cmd.Context(), function)
err = runAddEnvsPrompt(cmd.Context(), kc, function)
case "Labels":
err = runAddLabelsPrompt(cmd.Context(), function, common.DefaultLoaderSaver)
case "Git":
Expand Down
12 changes: 8 additions & 4 deletions cmd/config_envs.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ set environment variable from a secret
return loadSaver.Save(function)
}

return runAddEnvsPrompt(cmd.Context(), function)
kc, err := newK8sClientFromConfig(function.Deploy.Cluster, "", function.Deploy.Namespace, function.Local)
if err != nil {
return err
}
return runAddEnvsPrompt(cmd.Context(), kc, function)
},
}

Expand Down Expand Up @@ -211,7 +215,7 @@ func listEnvs(f fn.Function, w io.Writer, outputFormat Format) error {
}
}

func runAddEnvsPrompt(ctx context.Context, f fn.Function) (err error) {
func runAddEnvsPrompt(ctx context.Context, kc *k8s.Client, f fn.Function) (err error) {

insertToIndex := 0

Expand Down Expand Up @@ -243,11 +247,11 @@ func runAddEnvsPrompt(ctx context.Context, f fn.Function) (err error) {
}

// SECTION - select the type of Environment variable to be added
secrets, err := k8s.ListSecretsNamesIfConnected(ctx, f.Deploy.Namespace)
secrets, err := k8s.ListSecretsNamesIfConnected(ctx, kc, f.Deploy.Namespace)
if err != nil {
return
}
configMaps, err := k8s.ListConfigMapsNamesIfConnected(ctx, f.Deploy.Namespace)
configMaps, err := k8s.ListConfigMapsNamesIfConnected(ctx, kc, f.Deploy.Namespace)
if err != nil {
return
}
Expand Down
14 changes: 9 additions & 5 deletions cmd/config_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ For non-interactive usage, use flags to specify the volume type and configuratio
}

// Fall back to interactive mode
return runAddVolumesPrompt(cmd.Context(), function)
kc, err := newK8sClientFromConfig(function.Deploy.Cluster, "", function.Deploy.Namespace, function.Local)
if err != nil {
return err
}
return runAddVolumesPrompt(cmd.Context(), kc, function)
},
}

Expand Down Expand Up @@ -164,17 +168,17 @@ func listVolumes(f fn.Function) {
}
}

func runAddVolumesPrompt(ctx context.Context, f fn.Function) (err error) {
func runAddVolumesPrompt(ctx context.Context, kc *k8s.Client, f fn.Function) (err error) {

secrets, err := k8s.ListSecretsNamesIfConnected(ctx, f.Deploy.Namespace)
secrets, err := k8s.ListSecretsNamesIfConnected(ctx, kc, f.Deploy.Namespace)
if err != nil {
return
}
configMaps, err := k8s.ListConfigMapsNamesIfConnected(ctx, f.Deploy.Namespace)
configMaps, err := k8s.ListConfigMapsNamesIfConnected(ctx, kc, f.Deploy.Namespace)
if err != nil {
return
}
persistentVolumeClaims, err := k8s.ListPersistentVolumeClaimsNamesIfConnected(ctx, f.Deploy.Namespace)
persistentVolumeClaims, err := k8s.ListPersistentVolumeClaimsNamesIfConnected(ctx, kc, f.Deploy.Namespace)
if err != nil {
return
}
Expand Down
Loading
Loading