Skip to content
This repository has been archived by the owner on Jun 13, 2021. It is now read-only.

Commit

Permalink
Move the inspect command to "image inspect"
Browse files Browse the repository at this point in the history
The inspect command needed a bunch of code that was only present in the
"internal/commands" package. The patch is big but it's only moving code
around:

* cnab.go was split into multiple files:
  * credentials.go -> all things credentials
  * driver/docker.go -> mainly for the driver.Prepare that all the
commands use
  * registry.go -> has the method to get insecure registries from engine

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
  • Loading branch information
rumpl committed Oct 17, 2019
1 parent c622dcf commit 12fa9c0
Show file tree
Hide file tree
Showing 25 changed files with 680 additions and 608 deletions.
6 changes: 3 additions & 3 deletions e2e/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,19 @@ func TestInspectApp(t *testing.T) {
fs.WithDir("attachments.dockerapp", fs.FromDir("testdata/attachments.dockerapp")))
defer dir.Remove()

cmd.Command = dockerCli.Command("app", "inspect")
cmd.Command = dockerCli.Command("app", "image", "inspect")
cmd.Dir = dir.Path()
icmd.RunCmd(cmd).Assert(t, icmd.Expected{
ExitCode: 1,
Err: `"docker app inspect" requires exactly 1 argument.`,
Err: `"docker app image inspect" requires exactly 1 argument.`,
})

contextPath := filepath.Join("testdata", "simple")
cmd.Command = dockerCli.Command("app", "build", "--tag", "simple-app:1.0.0", contextPath)
cmd.Dir = ""
icmd.RunCmd(cmd).Assert(t, icmd.Success)

cmd.Command = dockerCli.Command("app", "inspect", "simple-app:1.0.0")
cmd.Command = dockerCli.Command("app", "image", "inspect", "simple-app:1.0.0")
cmd.Dir = dir.Path()
output := icmd.RunCmd(cmd).Assert(t, icmd.Success).Combined()
golden.Assert(t, output, "app-inspect.golden")
Expand Down
1 change: 0 additions & 1 deletion e2e/testdata/plugin-usage-experimental.golden
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Management Commands:
Commands:
build Build service images for the application
init Initialize Docker Application definition
inspect Shows metadata, parameters and a summary of the Compose file for a given application
ls List the installations and their last known installation result
pull Pull an application package from a registry
push Push an application package to a registry
Expand Down
1 change: 0 additions & 1 deletion e2e/testdata/plugin-usage.golden
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Management Commands:
Commands:
build Build service images for the application
init Initialize Docker Application definition
inspect Shows metadata, parameters and a summary of the Compose file for a given application
ls List the installations and their last known installation result
pull Pull an application package from a registry
push Push an application package to a registry
Expand Down
138 changes: 138 additions & 0 deletions internal/cnab/cnab.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package cnab

import (
"context"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/deislabs/cnab-go/bundle"
"github.com/docker/app/internal"
"github.com/docker/app/internal/log"
"github.com/docker/app/internal/packager"
"github.com/docker/app/internal/store"
appstore "github.com/docker/app/internal/store"
"github.com/docker/cli/cli/command"
"github.com/docker/cnab-to-oci/remotes"
"github.com/docker/distribution/reference"
)

type nameKind uint

const (
_ nameKind = iota
nameKindEmpty
nameKindFile
nameKindDir
nameKindReference
)

func getAppNameKind(name string) (string, nameKind) {
if name == "" {
return name, nameKindEmpty
}
// name can be a bundle.json or bundle.cnab file, or a dockerapp directory
st, err := os.Stat(name)
if os.IsNotExist(err) {
// try with .dockerapp extension
st, err = os.Stat(name + internal.AppExtension)
if err == nil {
name += internal.AppExtension
}
}
if err != nil {
return name, nameKindReference
}
if st.IsDir() {
return name, nameKindDir
}
return name, nameKindFile
}

func extractAndLoadAppBasedBundle(dockerCli command.Cli, name string) (*bundle.Bundle, string, error) {
app, err := packager.Extract(name)
if err != nil {
return nil, "", err
}
defer app.Cleanup()
bndl, err := packager.MakeBundleFromApp(dockerCli, app, nil)
return bndl, "", err
}

func loadBundleFromFile(filename string) (*bundle.Bundle, error) {
b := &bundle.Bundle{}
data, err := ioutil.ReadFile(filename)
if err != nil {
return b, err
}
return bundle.Unmarshal(data)
}

// ResolveBundle looks for a CNAB bundle which can be in a Docker App Package format or
// a bundle stored locally or in the bundle store. It returns a built or found bundle,
// a reference to the bundle if it is found in the bundlestore, and an error.
func ResolveBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, name string) (*bundle.Bundle, string, error) {
// resolution logic:
// - if there is a docker-app package in working directory, or an http:// / https:// prefix, use packager.Extract result
// - the name has a .json or .cnab extension and refers to an existing file or web resource: load the bundle
// - name matches a bundle name:version stored in the bundle store: use it
// - pull the bundle from the registry and add it to the bundle store
name, kind := getAppNameKind(name)
switch kind {
case nameKindFile:
if strings.HasSuffix(name, internal.AppExtension) {
return extractAndLoadAppBasedBundle(dockerCli, name)
}
bndl, err := loadBundleFromFile(name)
return bndl, "", err
case nameKindDir, nameKindEmpty:
return extractAndLoadAppBasedBundle(dockerCli, name)
case nameKindReference:
bndl, tagRef, err := GetBundle(dockerCli, bundleStore, name)
if err != nil {
return nil, "", err
}
return bndl, tagRef.String(), err
}
return nil, "", fmt.Errorf("could not resolve bundle %q", name)
}

// GetBundle searches for the bundle locally and tries to pull it if not found
func GetBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, name string) (*bundle.Bundle, reference.Reference, error) {
ref, err := store.StringToRef(name)
if err != nil {
return nil, nil, err
}
bndl, err := bundleStore.Read(ref)
if err != nil {
fmt.Fprintf(dockerCli.Err(), "Unable to find application image %q locally\n", reference.FamiliarString(ref))

fmt.Fprintf(dockerCli.Out(), "Pulling from registry...\n")
if named, ok := ref.(reference.Named); ok {
bndl, err = PullBundle(dockerCli, bundleStore, named)
if err != nil {
return nil, nil, err
}
}
}

return bndl, ref, nil
}

// PullBundle pulls the bundle and stores it into the bundle store
func PullBundle(dockerCli command.Cli, bundleStore appstore.BundleStore, tagRef reference.Named) (*bundle.Bundle, error) {
insecureRegistries, err := internal.InsecureRegistriesFromEngine(dockerCli)
if err != nil {
return nil, fmt.Errorf("could not retrieve insecure registries: %v", err)
}

bndl, err := remotes.Pull(log.WithLogContext(context.Background()), reference.TagNameOnly(tagRef), remotes.CreateResolver(dockerCli.ConfigFile(), insecureRegistries...))
if err != nil {
return nil, err
}
if _, err := bundleStore.Store(tagRef, bndl); err != nil {
return nil, err
}
return bndl, nil
}
115 changes: 115 additions & 0 deletions internal/cnab/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package cnab

import (
"bytes"
"io"
"os"
"strings"

"github.com/deislabs/cnab-go/claim"
"github.com/deislabs/cnab-go/driver"
dockerDriver "github.com/deislabs/cnab-go/driver/docker"
"github.com/docker/app/internal"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
)

// BindMount
type BindMount struct {
required bool
endpoint string
}

const defaultSocketPath string = "/var/run/docker.sock"

func RequiredClaimBindMount(c claim.Claim, targetContextName string, dockerCli command.Cli) (BindMount, error) {
var specifiedOrchestrator string
if rawOrchestrator, ok := c.Parameters[internal.ParameterOrchestratorName]; ok {
specifiedOrchestrator = rawOrchestrator.(string)
}

return RequiredBindMount(targetContextName, specifiedOrchestrator, dockerCli.ContextStore())
}

// RequiredBindMount Returns the path required to bind mount when running
// the invocation image.
func RequiredBindMount(targetContextName string, targetOrchestrator string, s store.Store) (BindMount, error) {
if targetOrchestrator == "kubernetes" {
return BindMount{}, nil
}

if targetContextName == "" {
targetContextName = "default"
}

// in case of docker desktop, we want to rewrite the context in cases where it targets the local swarm or Kubernetes
s = &internal.DockerDesktopAwareStore{Store: s}

ctxMeta, err := s.GetMetadata(targetContextName)
if err != nil {
return BindMount{}, err
}
dockerCtx, err := command.GetDockerContext(ctxMeta)
if err != nil {
return BindMount{}, err
}
if dockerCtx.StackOrchestrator == command.OrchestratorKubernetes {
return BindMount{}, nil
}
dockerEndpoint, err := docker.EndpointFromContext(ctxMeta)
if err != nil {
return BindMount{}, err
}

host := dockerEndpoint.Host
return BindMount{isDockerHostLocal(host), socketPath(host)}, nil
}

func socketPath(host string) string {
if strings.HasPrefix(host, "unix://") {
return strings.TrimPrefix(host, "unix://")
}

return defaultSocketPath
}

func isDockerHostLocal(host string) bool {
return host == "" || strings.HasPrefix(host, "unix://") || strings.HasPrefix(host, "npipe://")
}

// PrepareDriver prepares a driver per the user's request.
func PrepareDriver(dockerCli command.Cli, bindMount BindMount, stdout io.Writer) (driver.Driver, *bytes.Buffer) {
d := &dockerDriver.Driver{}
errBuf := bytes.NewBuffer(nil)
d.SetDockerCli(dockerCli)
if stdout != nil {
d.SetContainerOut(stdout)
}
d.SetContainerErr(errBuf)
if bindMount.required {
d.AddConfigurationOptions(func(config *container.Config, hostConfig *container.HostConfig) error {
config.User = "0:0"
mounts := []mount.Mount{
{
Type: mount.TypeBind,
Source: bindMount.endpoint,
Target: bindMount.endpoint,
},
}
hostConfig.Mounts = mounts
return nil
})
}

// Load any driver-specific config out of the environment.
driverCfg := map[string]string{}
for env := range d.Config() {
driverCfg[env] = os.Getenv(env)
}
d.SetConfig(driverCfg)

return d, errBuf
}
Loading

0 comments on commit 12fa9c0

Please sign in to comment.