This repository has been archived by the owner on Jan 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
local.go
126 lines (102 loc) · 3 KB
/
local.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package repository_fetcher
import (
"errors"
"fmt"
"net/url"
"os"
"sync"
"time"
"code.cloudfoundry.org/garden-shed/layercake"
"code.cloudfoundry.org/lager"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/archive"
)
//go:generate counterfeiter -o fake_container_id_provider/FakeContainerIDProvider.go . ContainerIDProvider
type ContainerIDProvider interface {
ProvideID(path string) layercake.ID
}
type Local struct {
Cake layercake.Cake
DefaultRootFSPath string
IDProvider ContainerIDProvider
mu sync.RWMutex
}
func (l *Local) Fetch(log lager.Logger, repoURL *url.URL, _, _ string, _ int64) (*Image, error) {
log = log.Session("local-fetch", lager.Data{"path": repoURL})
log.Info("start")
defer log.Info("end")
path := repoURL.Path
if len(path) == 0 {
path = l.DefaultRootFSPath
}
if len(path) == 0 {
return nil, errors.New("RootFSPath: is a required parameter, since no default rootfs was provided to the server.")
}
id, err := l.fetch(log, path)
return &Image{
ImageID: id,
}, err
}
func (l *Local) FetchID(log lager.Logger, repoURL *url.URL) (layercake.ID, error) {
return l.IDProvider.ProvideID(repoURL.Path), nil
}
func (l *Local) fetch(log lager.Logger, path string) (string, error) {
path, err := resolve(path)
if err != nil {
return "", err
}
id := l.IDProvider.ProvideID(path)
// synchronize all downloads, we could optimize by only mutexing around each
// particular rootfs path, but in practice importing local rootfses is decently fast,
// and concurrently importing local rootfses is rare.
l.mu.Lock()
defer l.mu.Unlock()
if _, err := l.Cake.Get(id); err == nil {
log.Info("using-cache", lager.Data{"graphID": id.GraphID()})
return id.GraphID(), nil // use cache
}
tar, err := archive.Tar(path, archive.Uncompressed)
if err != nil {
return "", fmt.Errorf("repository_fetcher: fetch local rootfs: untar rootfs: %v", err)
}
defer tar.Close()
if err := l.Cake.Register(&image.Image{ID: id.GraphID()}, tar); err != nil {
return "", fmt.Errorf("repository_fetcher: fetch local rootfs: register rootfs: %v", err)
}
log.Info("fetched-uncached-rootfs", lager.Data{"graphID": id.GraphID()})
return id.GraphID(), nil
}
func resolve(path string) (string, error) {
fileInfo, err := os.Lstat(path)
if err != nil {
return "", fmt.Errorf("repository_fetcher: stat file: %s", err)
}
if (fileInfo.Mode() & os.ModeSymlink) == os.ModeSymlink {
if path, err = os.Readlink(path); err != nil {
return "", fmt.Errorf("repository_fetcher: read link: %s", err)
}
}
return path, nil
}
type LayerIDProvider struct {
}
func (LayerIDProvider) ProvideID(path string) layercake.ID {
path, err := resolve(path)
if err != nil {
return layercake.LocalImageID{
Path: path,
ModifiedTime: time.Time{},
}
}
info, err := os.Lstat(path)
if err != nil {
return layercake.LocalImageID{
Path: path,
ModifiedTime: time.Time{},
}
}
return layercake.LocalImageID{
Path: path,
ModifiedTime: info.ModTime(),
}
}