Skip to content

Commit

Permalink
*: pluggable transports
Browse files Browse the repository at this point in the history
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
  • Loading branch information
runcom committed Feb 20, 2017
1 parent 3f493f2 commit add4ea6
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 53 deletions.
5 changes: 5 additions & 0 deletions directory/directory_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ import (
"github.com/containers/image/directory/explicitfilepath"
"github.com/containers/image/docker/reference"
"github.com/containers/image/image"
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/opencontainers/go-digest"
)

func init() {
transports.Register(Transport)
}

// Transport is an ImageTransport for directory paths.
var Transport = dirTransport{}

Expand Down
5 changes: 5 additions & 0 deletions docker/daemon/daemon_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ import (

"github.com/containers/image/docker/reference"
"github.com/containers/image/image"
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/opencontainers/go-digest"
)

func init() {
transports.Register(Transport)
}

// Transport is an ImageTransport for images managed by a local Docker daemon.
var Transport = daemonTransport{}

Expand Down
5 changes: 5 additions & 0 deletions docker/docker_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import (

"github.com/containers/image/docker/policyconfiguration"
"github.com/containers/image/docker/reference"
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/pkg/errors"
)

func init() {
transports.Register(Transport)
}

// Transport is an ImageTransport for Docker registry-hosted images.
var Transport = dockerTransport{}

Expand Down
5 changes: 5 additions & 0 deletions oci/layout/oci_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ import (
"github.com/containers/image/directory/explicitfilepath"
"github.com/containers/image/docker/reference"
"github.com/containers/image/image"
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)

func init() {
transports.Register(Transport)
}

// Transport is an ImageTransport for OCI directories.
var Transport = ociTransport{}

Expand Down
5 changes: 5 additions & 0 deletions openshift/openshift_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ import (
"github.com/containers/image/docker/policyconfiguration"
"github.com/containers/image/docker/reference"
genericImage "github.com/containers/image/image"
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/pkg/errors"
)

func init() {
transports.Register(Transport)
}

// Transport is an ImageTransport for OpenShift registry-hosted images.
var Transport = openshiftTransport{}

Expand Down
8 changes: 3 additions & 5 deletions signature/policy_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,8 @@ func (m *policyTransportsMap) UnmarshalJSON(data []byte) error {
// So, use a temporary map of pointers-to-slices and convert.
tmpMap := map[string]*PolicyTransportScopes{}
if err := paranoidUnmarshalJSONObject(data, func(key string) interface{} {
transport, ok := transports.KnownTransports[key]
if !ok {
return nil
}
// transport can be nil
transport := transports.Get(key)
// paranoidUnmarshalJSONObject detects key duplication for us, check just to be safe.
if _, ok := tmpMap[key]; ok {
return nil
Expand Down Expand Up @@ -174,7 +172,7 @@ func (m *policyTransportScopesWithTransport) UnmarshalJSON(data []byte) error {
if _, ok := tmpMap[key]; ok {
return nil
}
if key != "" {
if key != "" && m.transport != nil {
if err := m.transport.ValidatePolicyConfigurationScope(key); err != nil {
return nil
}
Expand Down
4 changes: 1 addition & 3 deletions signature/policy_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/containers/image/directory"
"github.com/containers/image/docker"
_ "github.com/containers/image/openshift"
"github.com/containers/image/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -269,9 +270,6 @@ func TestPolicyUnmarshalJSON(t *testing.T) {
func(v mSI) { v["transports"] = []string{} },
// "default" is an invalid PolicyRequirements
func(v mSI) { v["default"] = PolicyRequirements{} },
// A key in "transports" is an invalid transport name
func(v mSI) { x(v, "transports")["this is unknown"] = x(v, "transports")["docker"] },
func(v mSI) { x(v, "transports")[""] = x(v, "transports")["docker"] },
}
for _, fn := range breakFns {
err = tryUnmarshalModifiedPolicy(t, &p, validJSON, fn)
Expand Down
5 changes: 5 additions & 0 deletions storage/storage_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ import (

"github.com/Sirupsen/logrus"
"github.com/containers/image/docker/reference"
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/containers/storage/storage"
"github.com/opencontainers/go-digest"
ddigest "github.com/opencontainers/go-digest"
)

func init() {
transports.Register(Transport)
}

var (
// Transport is an ImageTransport that uses either a default
// storage.Store or one that's it's explicitly told to use.
Expand Down
31 changes: 31 additions & 0 deletions transports/alltransports/alltransports.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package alltransports

import (
"strings"

// register all known transports
// NOTE: Make sure docs/policy.json.md is updated when adding or updating
// a transport.
_ "github.com/containers/image/directory"
_ "github.com/containers/image/docker"
_ "github.com/containers/image/docker/daemon"
_ "github.com/containers/image/oci/layout"
_ "github.com/containers/image/openshift"
_ "github.com/containers/image/storage"
"github.com/containers/image/transports"
"github.com/containers/image/types"
"github.com/pkg/errors"
)

// ParseImageName converts a URL-like image name to a types.ImageReference.
func ParseImageName(imgName string) (types.ImageReference, error) {
parts := strings.SplitN(imgName, ":", 2)
if len(parts) != 2 {
return nil, errors.Errorf(`Invalid image name "%s", expected colon-separated transport:reference`, imgName)
}
transport := transports.Get(parts[0])
if transport == nil {
return nil, errors.Errorf(`Invalid image name "%s", unknown transport "%s"`, imgName, parts[0])
}
return transport.ParseReference(parts[1])
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package transports
package alltransports

import (
"testing"

"github.com/containers/image/transports"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestKnownTransports(t *testing.T) {
assert.NotNil(t, KnownTransports) // Ensure that the initialization has actually been run
assert.True(t, len(KnownTransports) > 1)
}

func TestParseImageName(t *testing.T) {
// This primarily tests error handling, TestImageNameHandling is a table-driven
// test for the expected values.
Expand All @@ -36,11 +32,12 @@ func TestImageNameHandling(t *testing.T) {
{"docker-daemon", "busybox:latest", "busybox:latest"},
{"oci", "/etc:sometag", "/etc:sometag"},
// "atomic" not tested here because it depends on per-user configuration for the default cluster.
// "containers-storage" not tested here because it needs to initialize various directories on the fs.
} {
fullInput := c.transport + ":" + c.input
ref, err := ParseImageName(fullInput)
require.NoError(t, err, fullInput)
s := ImageName(ref)
s := transports.ImageName(ref)
assert.Equal(t, c.transport+":"+c.roundtrip, s, fullInput)
}
}
74 changes: 36 additions & 38 deletions transports/transports.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,50 @@ package transports

import (
"fmt"
"strings"

"github.com/containers/image/directory"
"github.com/containers/image/docker"
"github.com/containers/image/docker/daemon"
ociLayout "github.com/containers/image/oci/layout"
"github.com/containers/image/openshift"
"github.com/containers/image/storage"
"sync"

"github.com/containers/image/types"
"github.com/pkg/errors"
)

// KnownTransports is a registry of known ImageTransport instances.
var KnownTransports map[string]types.ImageTransport
// knownTransports is a registry of known ImageTransport instances.
type knownTransports struct {
transports map[string]types.ImageTransport
mu sync.Mutex
}

func init() {
KnownTransports = make(map[string]types.ImageTransport)
// NOTE: Make sure docs/policy.json.md is updated when adding or updating
// a transport.
for _, t := range []types.ImageTransport{
directory.Transport,
docker.Transport,
daemon.Transport,
ociLayout.Transport,
openshift.Transport,
storage.Transport,
} {
name := t.Name()
if _, ok := KnownTransports[name]; ok {
panic(fmt.Sprintf("Duplicate image transport name %s", name))
}
KnownTransports[name] = t
}
func (kt *knownTransports) Get(k string) types.ImageTransport {
kt.mu.Lock()
t := kt.transports[k]
kt.mu.Unlock()
return t
}

// ParseImageName converts a URL-like image name to a types.ImageReference.
func ParseImageName(imgName string) (types.ImageReference, error) {
parts := strings.SplitN(imgName, ":", 2)
if len(parts) != 2 {
return nil, errors.Errorf(`Invalid image name "%s", expected colon-separated transport:reference`, imgName)
func (kt *knownTransports) Add(t types.ImageTransport) {
kt.mu.Lock()
name := t.Name()
if t := kt.transports[name]; t != nil {
panic(fmt.Sprintf("Duplicate image transport name %s", name))
}
transport, ok := KnownTransports[parts[0]]
if !ok {
return nil, errors.Errorf(`Invalid image name "%s", unknown transport "%s"`, imgName, parts[0])
kt.transports[name] = t
kt.mu.Unlock()
}

var kt *knownTransports

func init() {
kt = &knownTransports{
transports: make(map[string]types.ImageTransport),
}
return transport.ParseReference(parts[1])
}

// Get TODO(runcom)
func Get(name string) types.ImageTransport {
return kt.Get(name)
}

// Register TODO(runcom)
func Register(t types.ImageTransport) {
kt.Add(t)
}

// ImageName converts a types.ImageReference into an URL-like image name, which MUST be such that
Expand Down

0 comments on commit add4ea6

Please sign in to comment.