Skip to content

Commit

Permalink
Merge pull request #75 from ivanilves/debloat-local
Browse files Browse the repository at this point in the history
Debloat local
  • Loading branch information
vonrabbe authored Oct 16, 2017
2 parents 86595fe + c7ed971 commit 38d46b7
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 221 deletions.
28 changes: 0 additions & 28 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,34 +105,6 @@ func DoesMatch(s, ex string) bool {
return matched
}

func isHostname(s string) bool {
if strings.Contains(s, ".") {
return true
}

if strings.Contains(s, ":") {
return true
}

if s == "localhost" {
return true
}

return false
}

// GetRegistryNameFromRepo tries to get Docker registry name from repository name
// .. if it is not possible it returns default registry name (usually Docker Hub)
func GetRegistryNameFromRepo(repository, defaultRegistry string) string {
r := strings.Split(repository, "/")[0]

if isHostname(r) {
return r
}

return defaultRegistry
}

// GeneratePathFromHostname generates "/"-delimited path from a hostname[:port]
func GeneratePathFromHostname(hostname string) string {
allParts := strings.Split(hostname, ":")
Expand Down
22 changes: 0 additions & 22 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,28 +79,6 @@ func TestDoesMatch(t *testing.T) {
}
}

func TestGetRegistryNameFromRepo(t *testing.T) {
expected := map[string]string{
"mesosphere/marathon": dockerHub,
"bogohost/my/inner/troll": dockerHub,
"registry.hipsta.io/hype/hotshit": "registry.hipsta.io",
"localhost/my/image": "localhost",
"bogohost:5000/mymymy/img": "bogohost:5000",
}

for repo, expectedRegistryName := range expected {
registryName := GetRegistryNameFromRepo(repo, dockerHub)

if registryName != expectedRegistryName {
t.Fatalf(
"Got unexpected Docker registry name '%s' from repo '%s' (expected: '%s')",
registryName,
repo,
expectedRegistryName,
)
}
}
}
func TestGeneratePathFromHostname(t *testing.T) {
examples := map[string]string{
"localhost": "/localhost",
Expand Down
46 changes: 46 additions & 0 deletions docker/client/api/version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package version

import (
"encoding/json"
"io"
"net/http"
"time"

"github.com/tv42/httpunix"
)

// Detect detects Docker API version through the passed Docker socket
func Detect(dockerSocket string) (string, error) {
hc := http.Client{Transport: getTransport(dockerSocket)}

resp, err := hc.Get("http+unix://docker/version")
if err != nil {
return "", err
}

return parseJSON(resp.Body)
}

func getTransport(dockerSocket string) *httpunix.Transport {
t := &httpunix.Transport{
DialTimeout: 200 * time.Millisecond,
RequestTimeout: 2 * time.Second,
ResponseHeaderTimeout: 2 * time.Second,
}
t.RegisterLocation("docker", dockerSocket)

return t
}

func parseJSON(data io.ReadCloser) (string, error) {
v := struct {
APIVersion string `json:"ApiVersion"`
}{}

err := json.NewDecoder(data).Decode(&v)
if err != nil {
return "", err
}

return v.APIVersion, nil
}
28 changes: 28 additions & 0 deletions docker/client/api/version/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package version

import (
"testing"
)

const dockerSocket = "/var/run/docker.sock"
const invalidSocket = "/var/run/somethinginvalid.sock"

func TestDetect(t *testing.T) {
_, err := Detect(dockerSocket)
if err != nil {
t.Fatalf(
"Unable to detect Docker API version: %s",
err.Error(),
)
}
}

func TestWithInvalidSocket(t *testing.T) {
_, err := Detect(invalidSocket)
if err == nil {
t.Fatalf(
"Unable to detect Docker API version: %s",
err.Error(),
)
}
}
108 changes: 108 additions & 0 deletions docker/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package client

import (
"io/ioutil"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/moby/moby/client"

"golang.org/x/net/context"

"github.com/ivanilves/lstags/docker"
"github.com/ivanilves/lstags/docker/client/api/version"
"github.com/ivanilves/lstags/docker/config"
)

// DockerSocket is a socket we use to connect to the Docker daemon
var DockerSocket = "/var/run/docker.sock"

// DockerClient is a raw Docker client convenience wrapper
type DockerClient struct {
cli *client.Client
cnf *config.Config
}

// New creates new instance of DockerClient (our Docker client wrapper)
func New(cnf *config.Config) (*DockerClient, error) {
apiVersion, err := version.Detect(DockerSocket)
if err != nil {
return nil, err
}

cli, err := client.NewClient("unix://"+DockerSocket, apiVersion, nil, nil)
if err != nil {
return nil, err
}

return &DockerClient{cli: cli, cnf: cnf}, nil
}

// ListImagesForRepo lists images present locally for the repo specified
func (dc *DockerClient) ListImagesForRepo(repo string) ([]types.ImageSummary, error) {
listOptions, err := buildImageListOptions(repo)
if err != nil {
return nil, err
}

return dc.cli.ImageList(context.Background(), listOptions)
}

func buildImageListOptions(repo string) (types.ImageListOptions, error) {
repoFilter := "reference=" + repo
filterArgs := filters.NewArgs()

filterArgs, err := filters.ParseFlag(repoFilter, filterArgs)
if err != nil {
return types.ImageListOptions{}, err
}

return types.ImageListOptions{Filters: filterArgs}, nil
}

// Pull pulls Docker image specified
func (dc *DockerClient) Pull(ref string) error {
registryAuth, _ := dc.cnf.GetRegistryAuth(
docker.GetRegistry(ref),
)

pullOptions := types.ImagePullOptions{RegistryAuth: registryAuth}
if registryAuth == "" {
pullOptions = types.ImagePullOptions{}
}

resp, err := dc.cli.ImagePull(context.Background(), ref, pullOptions)
if err != nil {
return err
}

_, err = ioutil.ReadAll(resp)

return err
}

// Push pushes Docker image specified
func (dc *DockerClient) Push(ref string) error {
registryAuth, _ := dc.cnf.GetRegistryAuth(
docker.GetRegistry(ref),
)

pushOptions := types.ImagePushOptions{RegistryAuth: registryAuth}
if registryAuth == "" {
pushOptions = types.ImagePushOptions{}
}

resp, err := dc.cli.ImagePush(context.Background(), ref, pushOptions)
if err != nil {
return err
}

_, err = ioutil.ReadAll(resp)

return err
}

// Tag puts a "dst" tag on "src" Docker image
func (dc *DockerClient) Tag(src, dst string) error {
return dc.cli.ImageTag(context.Background(), src, dst)
}
36 changes: 36 additions & 0 deletions docker/docker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package docker

import (
"strings"
)

// DefaultRegistry is a registry we use if none could be resolved from image ref
var DefaultRegistry = "registry.hub.docker.com"

// GetRegistry tries to get Docker registry name from a repository or reference
// .. if it is not possible it returns default registry name (usually Docker Hub)
func GetRegistry(repoOrRef string) string {
r := strings.Split(repoOrRef, "/")[0]

if isHostname(r) {
return r
}

return DefaultRegistry
}

func isHostname(s string) bool {
if strings.Contains(s, ".") {
return true
}

if strings.Contains(s, ":") {
return true
}

if s == "localhost" {
return true
}

return false
}
32 changes: 32 additions & 0 deletions docker/docker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package docker

import (
"testing"
)

func TestGetRegistry(t *testing.T) {
examples := map[string]string{
"mesosphere/marathon": DefaultRegistry,
"bogohost/my/inner/troll": DefaultRegistry,
"bogohost/my/inner/troll:1.0.1": DefaultRegistry,
"registry.hipsta.io/hype/hotshit": "registry.hipsta.io",
"localhost/my/image": "localhost",
"localhost/my/image:latest": "localhost",
"bogohost:5000/mymymy/img": "bogohost:5000",
"bogohost:5000/mymymy/img:0.0.1": "bogohost:5000",
"bogohost:5000/mymymy/img:edge": "bogohost:5000",
}

for repoOrRef, expectedRegistry := range examples {
registry := GetRegistry(repoOrRef)

if registry != expectedRegistry {
t.Fatalf(
"Got unexpected Docker registry name '%s' from repo/ref '%s' (expected: '%s')",
registry,
repoOrRef,
expectedRegistry,
)
}
}
}
23 changes: 15 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"github.com/ivanilves/lstags/app"
"github.com/ivanilves/lstags/auth"
"github.com/ivanilves/lstags/docker"
dockerclient "github.com/ivanilves/lstags/docker/client"
dockerconfig "github.com/ivanilves/lstags/docker/config"
"github.com/ivanilves/lstags/tag"
"github.com/ivanilves/lstags/tag/local"
Expand Down Expand Up @@ -65,9 +67,9 @@ func main() {

pullAuths := make(map[string]string)

var pushAuth string
if o.PushRegistry != "" {
pushAuth, _ = dockerConfig.GetRegistryAuth(o.PushRegistry)
dc, err := dockerclient.New(dockerConfig)
if err != nil {
suicide(err)
}

type tagResult struct {
Expand All @@ -86,7 +88,7 @@ func main() {
suicide(err)
}

registryName := app.GetRegistryNameFromRepo(repository, o.DefaultRegistry)
registryName := docker.GetRegistry(repository)

repoRegistryName := registry.FormatRepoName(repository, registryName)
repoLocalName := local.FormatRepoName(repository, registryName)
Expand All @@ -106,7 +108,12 @@ func main() {
if err != nil {
suicide(err)
}
localTags, err := local.FetchTags(repoLocalName)

imageSummaries, err := dc.ListImagesForRepo(repoLocalName)
if err != nil {
suicide(err)
}
localTags, err := local.FetchTags(repoLocalName, imageSummaries)
if err != nil {
suicide(err)
}
Expand Down Expand Up @@ -168,7 +175,7 @@ func main() {
ref := repo + ":" + tg.GetName()

fmt.Printf("PULLING %s\n", ref)
err := local.Pull(ref, pullAuths[repo])
err := dc.Pull(ref)
if err != nil {
suicide(err)
}
Expand Down Expand Up @@ -208,12 +215,12 @@ func main() {

fmt.Printf("PUSHING %s => %s\n", srcRef, dstRef)

err := local.Tag(srcRef, dstRef)
err := dc.Tag(srcRef, dstRef)
if err != nil {
suicide(err)
}

err = local.Push(dstRef, pushAuth)
err = dc.Push(dstRef)
if err != nil {
suicide(err)
}
Expand Down
Loading

0 comments on commit 38d46b7

Please sign in to comment.