diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index bfb3f0174..b93222f4a 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -22,11 +22,12 @@ import ( "github.com/spf13/cobra" + "syscall" + "golang.org/x/crypto/ssh/terminal" "k8s.io/helm/pkg/getter" "k8s.io/helm/pkg/helm/helmpath" "k8s.io/helm/pkg/repo" - "syscall" ) type repoAddCmd struct { @@ -131,6 +132,30 @@ func addRepository(name, url, username, password string, home helmpath.Home, cer return fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error()) } + // Lock the repository file for concurrent processes synchronization and re-read its content before updating it + fd, err := syscall.Open(home.RepositoryFile(), syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0) + if err != nil { + return err + } + defer syscall.Close(fd) + + flock := syscall.Flock_t{ + Type: syscall.F_WRLCK, + Start: 0, + Len: 0, + Whence: io.SeekStart, + } + + syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock) + if err != nil { + return err + } + + f, err = repo.LoadRepositoriesFile(home.RepositoryFile()) + if err != nil { + return err + } + f.Update(&c) return f.WriteFile(home.RepositoryFile(), 0644) diff --git a/cmd/helm/repo_add_test.go b/cmd/helm/repo_add_test.go index 0b7650fb2..e8ad35086 100644 --- a/cmd/helm/repo_add_test.go +++ b/cmd/helm/repo_add_test.go @@ -128,6 +128,7 @@ func TestRepoAddConcurrentGoRoutines(t *testing.T) { wg.Add(3) for i := 0; i < 3; i++ { go func(name string) { + // TODO: launch repository additions in sub-processes as file locks are bound to processes, not file descriptors defer wg.Done() if err := addRepository(name, ts.URL(), "", "", settings.Home, "", "", "", true); err != nil { t.Error(err)