Exemple #1
0
func TestDistFromImageString(t *testing.T) {
	relPath1 := "some/relative/../path/with/dots/file.aci"
	absPath1, err := filepath.Abs(relPath1)
	if err != nil {

		t.Fatalf("unexpected error: %v", err)
	}
	relPath2 := "some/relative/../path/with/dots/file"
	absPath2, err := filepath.Abs(relPath2)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	tests := []struct {
		in         string
		distString string
		err        error
	}{
		// Appc
		{
			"example.com/app01",
			"cimd:appc:v=0:example.com/app01",
			nil,
		},
		{
			"example.com/app01:v1.0.0",
			"cimd:appc:v=0:example.com/app01?version=v1.0.0",
			nil,
		},
		{
			"example.com/app01:v1.0.0,label01=?&*/",
			"cimd:appc:v=0:example.com/app01?label01=%3F%26%2A%2F&version=v1.0.0",
			nil,
		},
		{
			"some-image-name",
			"cimd:appc:v=0:some-image-name",
			nil,
		},
		{
			"some-image-name:v1.0.0",
			"cimd:appc:v=0:some-image-name?version=v1.0.0",
			nil,
		},
		{
			"some-image-name:f6432b725a9a5f27eaecfa47a0cbab3c0ea00f22",
			"cimd:appc:v=0:some-image-name?version=f6432b725a9a5f27eaecfa47a0cbab3c0ea00f22",
			nil,
		},
		// ACIArchive
		{
			"file:///absolute/path/to/file.aci",
			"cimd:aci-archive:v=0:file%3A%2F%2F%2Fabsolute%2Fpath%2Fto%2Ffile.aci",
			nil,
		},
		{
			"/absolute/path/to/file.aci",
			"cimd:aci-archive:v=0:file%3A%2F%2F%2Fabsolute%2Fpath%2Fto%2Ffile.aci",
			nil,
		},
		{
			relPath1,
			"cimd:aci-archive:v=0:" + url.QueryEscape("file://"+absPath1),
			nil,
		},
		{
			"https://example.com/app.aci",
			"cimd:aci-archive:v=0:https%3A%2F%2Fexample.com%2Fapp.aci",
			nil,
		},
		// Path with no .aci extension
		{
			"/absolute/path/to/file",
			"",
			fmt.Errorf("invalid image string %q", "file:///absolute/path/to/file"),
		},
		{
			"/absolute/path/to/file.tar",
			"",
			fmt.Errorf("invalid image string %q", "file:///absolute/path/to/file.tar"),
		},
		{
			relPath2,
			"",
			fmt.Errorf("invalid image string %q", "file://"+absPath2),
		},
		// Docker
		{
			"docker:busybox",
			"cimd:docker:v=0:registry-1.docker.io/library/busybox:latest",
			nil,
		},
		{
			"docker://busybox",
			"cimd:docker:v=0:registry-1.docker.io/library/busybox:latest",
			nil,
		},
		{
			"docker:busybox:latest",
			"cimd:docker:v=0:registry-1.docker.io/library/busybox:latest",
			nil,
		},
		{
			"docker://*****:*****@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6",
			"cimd:docker:v=0:registry-1.docker.io/library/busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6",
			nil,
		},
		{
			"docker:myregistry.example.com:4000/busybox",
			"cimd:docker:v=0:myregistry.example.com:4000/busybox:latest",
			nil,
		},
		{
			"docker:myregistry.example.com:4000/busybox",
			"cimd:docker:v=0:myregistry.example.com:4000/busybox:latest",
			nil,
		},
		{
			"docker:myregistry.example.com:4000/busybox:1.0",
			"cimd:docker:v=0:myregistry.example.com:4000/busybox:1.0",
			nil,
		},
	}

	for _, tt := range tests {
		d, err := DistFromImageString(tt.in)
		if err != nil {
			if tt.err == nil {
				t.Fatalf("unexpected error: %v", err)
			}
			if tt.err.Error() != err.Error() {
				t.Fatalf("expected error %v, but got error %v", tt.err, err)
			}
			continue
		} else {
			if tt.err != nil {
				t.Fatalf("expected error %v, but got nil error", tt.err)
			}
		}
		td, err := dist.Parse(tt.distString)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if !d.Equals(td) {
			t.Fatalf("expected identical distribution but got %q != %q", tt.distString, d.CIMD().String())
		}
	}

}
Exemple #2
0
// DistFromImageString return the distribution for the given input image string
func DistFromImageString(is string) (dist.Distribution, error) {
	u, err := url.Parse(is)
	if err != nil {
		return nil, errwrap.Wrap(fmt.Errorf("failed to parse image url %q", is), err)
	}

	// Convert user friendly image string names to internal distribution URIs
	// file:///full/path/to/aci/file.aci -> archive:aci:file%3A%2F%2F%2Ffull%2Fpath%2Fto%2Faci%2Ffile.aci
	switch u.Scheme {
	case "":
		// no scheme given, hence it is an appc image name or path
		appImageType := guessAppcOrPath(is, []string{schema.ACIExtension})

		switch appImageType {
		case imageStringName:
			app, err := discovery.NewAppFromString(is)
			if err != nil {
				return nil, fmt.Errorf("invalid appc image string %q: %v", is, err)
			}
			return dist.NewAppcFromApp(app), nil
		case imageStringPath:
			absPath, err := filepath.Abs(is)
			if err != nil {
				return nil, errwrap.Wrap(fmt.Errorf("failed to get an absolute path for %q", is), err)
			}
			is = "file://" + absPath

			// given a file:// image string, call this function again to return an ACI distribution
			return DistFromImageString(is)
		default:
			return nil, fmt.Errorf("invalid image string type %q", appImageType)
		}
	case "file", "http", "https":
		// An ACI archive with any transport type (file, http, s3 etc...) and final aci extension
		if filepath.Ext(u.Path) == schema.ACIExtension {
			dist, err := dist.NewACIArchiveFromTransportURL(u)
			if err != nil {
				return nil, fmt.Errorf("archive distribution creation error: %v", err)
			}
			return dist, nil
		}
	case "docker":
		// Accept both docker: and docker:// uri
		dockerStr := is
		if strings.HasPrefix(dockerStr, "docker://") {
			dockerStr = strings.TrimPrefix(dockerStr, "docker://")
		} else if strings.HasPrefix(dockerStr, "docker:") {
			dockerStr = strings.TrimPrefix(dockerStr, "docker:")
		}

		dist, err := dist.NewDockerFromString(dockerStr)
		if err != nil {
			return nil, fmt.Errorf("docker distribution creation error: %v", err)
		}
		return dist, nil
	case dist.Scheme: // cimd
		return dist.Parse(is)
	default:
		// any other scheme is a an appc image name, i.e. "my-app:v1.0"
		app, err := discovery.NewAppFromString(is)
		if err != nil {
			return nil, fmt.Errorf("invalid appc image string %q: %v", is, err)
		}

		return dist.NewAppcFromApp(app), nil
	}

	return nil, fmt.Errorf("invalid image string %q", is)
}