mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Fix races on TagStore accessing
Docker-DCO-1.1-Signed-off-by: Alexandr Morozov <lk4d4math@gmail.com> (github: LK4D4)
This commit is contained in:
parent
838d6a9e9b
commit
c4990ab999
2 changed files with 44 additions and 24 deletions
|
@ -3,13 +3,15 @@ package graph
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/image"
|
|
||||||
"github.com/dotcloud/docker/utils"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/dotcloud/docker/image"
|
||||||
|
"github.com/dotcloud/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const DEFAULTTAG = "latest"
|
const DEFAULTTAG = "latest"
|
||||||
|
@ -18,6 +20,7 @@ type TagStore struct {
|
||||||
path string
|
path string
|
||||||
graph *Graph
|
graph *Graph
|
||||||
Repositories map[string]Repository
|
Repositories map[string]Repository
|
||||||
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type Repository map[string]string
|
type Repository map[string]string
|
||||||
|
@ -33,8 +36,8 @@ func NewTagStore(path string, graph *Graph) (*TagStore, error) {
|
||||||
Repositories: make(map[string]Repository),
|
Repositories: make(map[string]Repository),
|
||||||
}
|
}
|
||||||
// Load the json file if it exists, otherwise create it.
|
// Load the json file if it exists, otherwise create it.
|
||||||
if err := store.Reload(); os.IsNotExist(err) {
|
if err := store.reload(); os.IsNotExist(err) {
|
||||||
if err := store.Save(); err != nil {
|
if err := store.save(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -43,7 +46,7 @@ func NewTagStore(path string, graph *Graph) (*TagStore, error) {
|
||||||
return store, nil
|
return store, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) Save() error {
|
func (store *TagStore) save() error {
|
||||||
// Store the json ball
|
// Store the json ball
|
||||||
jsonData, err := json.Marshal(store)
|
jsonData, err := json.Marshal(store)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -55,7 +58,7 @@ func (store *TagStore) Save() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) Reload() error {
|
func (store *TagStore) reload() error {
|
||||||
jsonData, err := ioutil.ReadFile(store.path)
|
jsonData, err := ioutil.ReadFile(store.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -74,6 +77,8 @@ func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||||
tag = DEFAULTTAG
|
tag = DEFAULTTAG
|
||||||
}
|
}
|
||||||
img, err := store.GetImage(repos, tag)
|
img, err := store.GetImage(repos, tag)
|
||||||
|
store.Lock()
|
||||||
|
defer store.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if img == nil {
|
} else if img == nil {
|
||||||
|
@ -87,6 +92,8 @@ func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||||
// Return a reverse-lookup table of all the names which refer to each image
|
// Return a reverse-lookup table of all the names which refer to each image
|
||||||
// Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
|
// Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
|
||||||
func (store *TagStore) ByID() map[string][]string {
|
func (store *TagStore) ByID() map[string][]string {
|
||||||
|
store.Lock()
|
||||||
|
defer store.Unlock()
|
||||||
byID := make(map[string][]string)
|
byID := make(map[string][]string)
|
||||||
for repoName, repository := range store.Repositories {
|
for repoName, repository := range store.Repositories {
|
||||||
for tag, id := range repository {
|
for tag, id := range repository {
|
||||||
|
@ -130,8 +137,10 @@ func (store *TagStore) DeleteAll(id string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) Delete(repoName, tag string) (bool, error) {
|
func (store *TagStore) Delete(repoName, tag string) (bool, error) {
|
||||||
|
store.Lock()
|
||||||
|
defer store.Unlock()
|
||||||
deleted := false
|
deleted := false
|
||||||
if err := store.Reload(); err != nil {
|
if err := store.reload(); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if r, exists := store.Repositories[repoName]; exists {
|
if r, exists := store.Repositories[repoName]; exists {
|
||||||
|
@ -150,13 +159,15 @@ func (store *TagStore) Delete(repoName, tag string) (bool, error) {
|
||||||
deleted = true
|
deleted = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Errorf("No such repository: %s", repoName)
|
return false, fmt.Errorf("No such repository: %s", repoName)
|
||||||
}
|
}
|
||||||
return deleted, store.Save()
|
return deleted, store.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
|
func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
|
||||||
img, err := store.LookupImage(imageName)
|
img, err := store.LookupImage(imageName)
|
||||||
|
store.Lock()
|
||||||
|
defer store.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -169,7 +180,7 @@ func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
|
||||||
if err := validateTagName(tag); err != nil {
|
if err := validateTagName(tag); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := store.Reload(); err != nil {
|
if err := store.reload(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var repo Repository
|
var repo Repository
|
||||||
|
@ -183,11 +194,13 @@ func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
|
||||||
store.Repositories[repoName] = repo
|
store.Repositories[repoName] = repo
|
||||||
}
|
}
|
||||||
repo[tag] = img.ID
|
repo[tag] = img.ID
|
||||||
return store.Save()
|
return store.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *TagStore) Get(repoName string) (Repository, error) {
|
func (store *TagStore) Get(repoName string) (Repository, error) {
|
||||||
if err := store.Reload(); err != nil {
|
store.Lock()
|
||||||
|
defer store.Unlock()
|
||||||
|
if err := store.reload(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if r, exists := store.Repositories[repoName]; exists {
|
if r, exists := store.Repositories[repoName]; exists {
|
||||||
|
@ -198,6 +211,8 @@ func (store *TagStore) Get(repoName string) (Repository, error) {
|
||||||
|
|
||||||
func (store *TagStore) GetImage(repoName, tagOrID string) (*image.Image, error) {
|
func (store *TagStore) GetImage(repoName, tagOrID string) (*image.Image, error) {
|
||||||
repo, err := store.Get(repoName)
|
repo, err := store.Get(repoName)
|
||||||
|
store.Lock()
|
||||||
|
defer store.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if repo == nil {
|
} else if repo == nil {
|
||||||
|
@ -215,6 +230,20 @@ func (store *TagStore) GetImage(repoName, tagOrID string) (*image.Image, error)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (store *TagStore) GetRepoRefs() map[string][]string {
|
||||||
|
store.Lock()
|
||||||
|
reporefs := make(map[string][]string)
|
||||||
|
|
||||||
|
for name, repository := range store.Repositories {
|
||||||
|
for tag, id := range repository {
|
||||||
|
shortID := utils.TruncateID(id)
|
||||||
|
reporefs[shortID] = append(reporefs[shortID], fmt.Sprintf("%s:%s", name, tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
store.Unlock()
|
||||||
|
return reporefs
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the name of a repository
|
// Validate the name of a repository
|
||||||
func validateRepoName(name string) error {
|
func validateRepoName(name string) error {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
|
|
@ -684,15 +684,7 @@ func (srv *Server) ImagesViz(job *engine.Job) engine.Status {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reporefs := make(map[string][]string)
|
for id, repos := range srv.daemon.Repositories().GetRepoRefs() {
|
||||||
|
|
||||||
for name, repository := range srv.daemon.Repositories().Repositories {
|
|
||||||
for tag, id := range repository {
|
|
||||||
reporefs[utils.TruncateID(id)] = append(reporefs[utils.TruncateID(id)], fmt.Sprintf("%s:%s", name, tag))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for id, repos := range reporefs {
|
|
||||||
job.Stdout.Write([]byte(" \"" + id + "\" [label=\"" + id + "\\n" + strings.Join(repos, "\\n") + "\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n"))
|
job.Stdout.Write([]byte(" \"" + id + "\" [label=\"" + id + "\\n" + strings.Join(repos, "\\n") + "\",shape=box,fillcolor=\"paleturquoise\",style=\"filled,rounded\"];\n"))
|
||||||
}
|
}
|
||||||
job.Stdout.Write([]byte(" base [style=invisible]\n}\n"))
|
job.Stdout.Write([]byte(" base [style=invisible]\n}\n"))
|
||||||
|
@ -713,6 +705,7 @@ func (srv *Server) Images(job *engine.Job) engine.Status {
|
||||||
return job.Error(err)
|
return job.Error(err)
|
||||||
}
|
}
|
||||||
lookup := make(map[string]*engine.Env)
|
lookup := make(map[string]*engine.Env)
|
||||||
|
srv.daemon.Repositories().Lock()
|
||||||
for name, repository := range srv.daemon.Repositories().Repositories {
|
for name, repository := range srv.daemon.Repositories().Repositories {
|
||||||
if job.Getenv("filter") != "" {
|
if job.Getenv("filter") != "" {
|
||||||
if match, _ := path.Match(job.Getenv("filter"), name); !match {
|
if match, _ := path.Match(job.Getenv("filter"), name); !match {
|
||||||
|
@ -742,6 +735,7 @@ func (srv *Server) Images(job *engine.Job) engine.Status {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
srv.daemon.Repositories().Unlock()
|
||||||
|
|
||||||
outs := engine.NewTable("Created", len(lookup))
|
outs := engine.NewTable("Created", len(lookup))
|
||||||
for _, value := range lookup {
|
for _, value := range lookup {
|
||||||
|
@ -1303,9 +1297,6 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := srv.daemon.Repositories().Save(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue