diff --git a/internal/build/imgsrc/remote_image_resolver.go b/internal/build/imgsrc/remote_image_resolver.go index 3c146e34cb..3e7cf11117 100644 --- a/internal/build/imgsrc/remote_image_resolver.go +++ b/internal/build/imgsrc/remote_image_resolver.go @@ -5,14 +5,18 @@ import ( "fmt" "strconv" - "github.com/superfly/flyctl/internal/flyutil" + "github.com/superfly/fly-go" "github.com/superfly/flyctl/internal/tracing" "github.com/superfly/flyctl/iostreams" "go.opentelemetry.io/otel/trace" ) +type flyClient interface { + ResolveImageForApp(ctx context.Context, appName, imageRef string) (*fly.Image, error) +} + type remoteImageResolver struct { - flyApi flyutil.Client + flyApi flyClient } func (*remoteImageResolver) Name() string { @@ -46,9 +50,10 @@ func (s *remoteImageResolver) Run(ctx context.Context, _ *dockerClientFactory, s } di := &DeploymentImage{ - ID: img.ID, - Tag: img.Ref, - Size: int64(size), + ID: img.ID, + Tag: img.Ref, + Digest: img.Digest, + Size: int64(size), } span.SetAttributes(di.ToSpanAttributes()...) diff --git a/internal/build/imgsrc/resolver.go b/internal/build/imgsrc/resolver.go index ec30f82ec1..839b11080e 100644 --- a/internal/build/imgsrc/resolver.go +++ b/internal/build/imgsrc/resolver.go @@ -120,11 +120,19 @@ func (ro RefOptions) ToSpanAttributes() []attribute.KeyValue { type DeploymentImage struct { ID string Tag string + Digest string Size int64 BuildID string Labels map[string]string } +func (image *DeploymentImage) String() string { + if image.Digest == "" { + return image.Tag + } + return fmt.Sprintf("%s@%s", image.Tag, image.Digest) +} + func (di DeploymentImage) ToSpanAttributes() []attribute.KeyValue { attrs := []attribute.KeyValue{ attribute.String("image.id", di.ID), diff --git a/internal/build/imgsrc/resolver_test.go b/internal/build/imgsrc/resolver_test.go index d01312d6a7..42ec5073f3 100644 --- a/internal/build/imgsrc/resolver_test.go +++ b/internal/build/imgsrc/resolver_test.go @@ -12,6 +12,19 @@ import ( "github.com/superfly/flyctl/internal/config" ) +func TestDeploymentImage(t *testing.T) { + image := &DeploymentImage{ + ID: "img_8rlxp2nzn32np3jq", + Tag: "docker-hub-mirror.fly.io/flyio/postgres-flex:16", + Digest: "sha256:f107dbfaa732063b31ee94aa728c4f5648a672259fd62bfaa245f9b7a53b5479", + Size: 123, + } + assert.Equal(t, "docker-hub-mirror.fly.io/flyio/postgres-flex:16@sha256:f107dbfaa732063b31ee94aa728c4f5648a672259fd62bfaa245f9b7a53b5479", image.String()) + + image.Digest = "" + assert.Equal(t, "docker-hub-mirror.fly.io/flyio/postgres-flex:16", image.String()) +} + func TestHeartbeat(t *testing.T) { dc, err := client.NewClientWithOpts() assert.NoError(t, err) diff --git a/internal/command/command_run.go b/internal/command/command_run.go index 71d4a7cbbc..47da00f56d 100644 --- a/internal/command/command_run.go +++ b/internal/command/command_run.go @@ -108,7 +108,7 @@ func DetermineImage(ctx context.Context, appName string, imageOrPath string) (im return nil, errors.New("could not find an image to deploy") } - fmt.Fprintf(io.Out, "Image: %s\n", img.Tag) + fmt.Fprintf(io.Out, "Image: %s\n", img.String()) fmt.Fprintf(io.Out, "Image size: %s\n\n", humanize.Bytes(uint64(img.Size))) return img, nil diff --git a/internal/command/machine/run.go b/internal/command/machine/run.go index 164c133f2f..fb3ab6cfc5 100644 --- a/internal/command/machine/run.go +++ b/internal/command/machine/run.go @@ -803,7 +803,7 @@ func determineMachineConfig( if err != nil { return machineConf, err } - machineConf.Image = img.Tag + machineConf.Image = img.String() } // Service updates