Skip to content

Commit dc2fbee

Browse files
authored
fix: func deploy uses Docker API, not binary
Signed-off-by: Matej Vasek <mvasek@redhat.com>
1 parent 8a91cac commit dc2fbee

File tree

8 files changed

+313
-46
lines changed

8 files changed

+313
-46
lines changed

client.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type Builder interface {
4747
type Pusher interface {
4848
// Push the image of the Function.
4949
// Returns Image Digest - SHA256 hash of the produced image
50-
Push(Function) (string, error)
50+
Push(ctx context.Context, f Function) (string, error)
5151
}
5252

5353
// Deployer of Function source to running status.
@@ -270,7 +270,7 @@ func (c *Client) New(cfg Function) (err error) {
270270
// Deploy the initialized Function, returning its publicly
271271
// addressible name for possible registration.
272272
c.progressListener.Increment("Deploying Function to cluster")
273-
if err = c.Deploy(f.Root); err != nil {
273+
if err = c.Deploy(context.TODO(), f.Root); err != nil {
274274
return
275275
}
276276

@@ -404,7 +404,7 @@ func (c *Client) Build(path string) (err error) {
404404

405405
// Deploy the Function at path. Errors if the Function has not been
406406
// initialized with an image tag.
407-
func (c *Client) Deploy(path string) (err error) {
407+
func (c *Client) Deploy(ctx context.Context, path string) (err error) {
408408
f, err := NewFunction(path)
409409
if err != nil {
410410
return
@@ -418,7 +418,7 @@ func (c *Client) Deploy(path string) (err error) {
418418

419419
// Push the image for the named service to the configured registry
420420
fmt.Println("Pushing function image to the registry")
421-
imageDigest, err := c.pusher.Push(f)
421+
imageDigest, err := c.pusher.Push(ctx, f)
422422
if err != nil {
423423
return
424424
}
@@ -525,7 +525,7 @@ func (n *noopBuilder) Build(_ Function) error { return nil }
525525

526526
type noopPusher struct{ output io.Writer }
527527

528-
func (n *noopPusher) Push(_ Function) (string, error) { return "", nil }
528+
func (n *noopPusher) Push(ctx context.Context, f Function) (string, error) { return "", nil }
529529

530530
type noopDeployer struct{ output io.Writer }
531531

client_int_test.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package function_test
44

55
import (
6+
"context"
67
"os"
78
"reflect"
89
"testing"
@@ -115,7 +116,7 @@ func TestDeploy(t *testing.T) {
115116
}
116117
defer del(t, client, "deploy")
117118

118-
if err := client.Deploy("."); err != nil {
119+
if err := client.Deploy(context.TODO(), "."); err != nil {
119120
t.Fatal(err)
120121
}
121122
}
@@ -155,7 +156,10 @@ func newClient(verbose bool) *boson.Client {
155156
builder := buildpacks.NewBuilder()
156157
builder.Verbose = verbose
157158

158-
pusher := docker.NewPusher()
159+
pusher, err := docker.NewPusher()
160+
if err != nil {
161+
panic(err)
162+
}
159163
pusher.Verbose = verbose
160164

161165
deployer, err := knative.NewDeployer(DefaultNamespace)

client_test.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ func TestUpdate(t *testing.T) {
512512

513513
// Invoke the creation, triggering the Function delegates, and
514514
// perform follow-up assertions that the Functions were indeed invoked.
515-
if err := client.Deploy(root); err != nil {
515+
if err := client.Deploy(context.TODO(), root); err != nil {
516516
t.Fatal(err)
517517
}
518518

@@ -694,15 +694,14 @@ func TestDeployUnbuilt(t *testing.T) {
694694
}
695695

696696
// Now try to deploy it. Ie. without having run the necessary build step.
697-
err := client.Deploy(root)
697+
err := client.Deploy(context.TODO(), root)
698698
if err == nil {
699699
t.Fatal("did not receive an error attempting to deploy an unbuilt Function")
700700
}
701701

702702
if !errors.Is(err, bosonFunc.ErrNotBuilt) {
703703
t.Fatalf("did not receive expected error type. Expected ErrNotBuilt, got %T", err)
704704
}
705-
706705
}
707706

708707
// TODO: The tests which confirm an error is generated do not currently test

cmd/deploy.go

+94-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package cmd
22

33
import (
4+
"bufio"
5+
"context"
46
"fmt"
7+
"os"
8+
"strings"
59

10+
"github.com/containers/image/v5/pkg/docker/config"
11+
containersTypes "github.com/containers/image/v5/types"
612
"github.com/ory/viper"
13+
"github.com/pkg/errors"
714
"github.com/spf13/cobra"
15+
"golang.org/x/crypto/ssh/terminal"
816

917
bosonFunc "github.com/boson-project/func"
1018
"github.com/boson-project/func/buildpacks"
@@ -96,7 +104,10 @@ func runDeploy(cmd *cobra.Command, _ []string) (err error) {
96104
builder := buildpacks.NewBuilder()
97105
builder.Verbose = config.Verbose
98106

99-
pusher := docker.NewPusher()
107+
pusher, err := docker.NewPusher(docker.WithCredentialsProvider(credentialsProvider))
108+
if err != nil {
109+
return err
110+
}
100111
pusher.Verbose = config.Verbose
101112

102113
ns := config.Namespace
@@ -127,12 +138,93 @@ func runDeploy(cmd *cobra.Command, _ []string) (err error) {
127138
}
128139
}
129140

130-
return client.Deploy(config.Path)
141+
return client.Deploy(cmd.Context(), config.Path)
131142

132143
// NOTE: Namespace is optional, default is that used by k8s client
133144
// (for example kubectl usually uses ~/.kube/config)
134145
}
135146

147+
func credentialsProvider(ctx context.Context, registry string) (docker.Credentials, error) {
148+
149+
result := docker.Credentials{}
150+
credentials, err := config.GetCredentials(nil, registry)
151+
if err != nil {
152+
return result, errors.Wrap(err, "failed to get credentials")
153+
}
154+
155+
if credentials != (containersTypes.DockerAuthConfig{}) {
156+
result.Username, result.Password = credentials.Username, credentials.Password
157+
return result, nil
158+
}
159+
160+
fmt.Print("Username: ")
161+
username, err := getUserName(ctx)
162+
if err != nil {
163+
return result, err
164+
}
165+
166+
fmt.Print("Password: ")
167+
bytePassword, err := getPassword(ctx)
168+
if err != nil {
169+
return result, err
170+
}
171+
password := string(bytePassword)
172+
173+
result.Username, result.Password = username, password
174+
175+
return result, nil
176+
}
177+
178+
func getPassword(ctx context.Context) ([]byte, error) {
179+
ch := make(chan struct {
180+
p []byte
181+
e error
182+
})
183+
184+
go func() {
185+
pass, err := terminal.ReadPassword(0)
186+
ch <- struct {
187+
p []byte
188+
e error
189+
}{p: pass, e: err}
190+
}()
191+
192+
select {
193+
case res := <-ch:
194+
return res.p, res.e
195+
case <-ctx.Done():
196+
return nil, ctx.Err()
197+
}
198+
}
199+
200+
func getUserName(ctx context.Context) (string, error) {
201+
ch := make(chan struct {
202+
u string
203+
e error
204+
})
205+
go func() {
206+
reader := bufio.NewReader(os.Stdin)
207+
username, err := reader.ReadString('\n')
208+
if err != nil {
209+
ch <- struct {
210+
u string
211+
e error
212+
}{u: "", e: err}
213+
}
214+
ch <- struct {
215+
u string
216+
e error
217+
}{u: strings.TrimRight(username, "\n"), e: nil}
218+
}()
219+
220+
select {
221+
case res := <-ch:
222+
return res.u, res.e
223+
case <-ctx.Done():
224+
return "", ctx.Err()
225+
}
226+
}
227+
136228
type deployConfig struct {
137229
buildConfig
138230

0 commit comments

Comments
 (0)