mirror of https://github.com/docker/docs.git
Merge pull request #428 from docker/merge-bootstrap-and-update
Combine bootstrapClient and tuf/client's Client.Update into a single Update function
This commit is contained in:
commit
160980db89
104
client/client.go
104
client/client.go
|
@ -2,10 +2,10 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -40,19 +40,12 @@ func init() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrRepoNotInitialized is returned when trying to can publish on an uninitialized
|
// ErrRepoNotInitialized is returned when trying to publish an uninitialized
|
||||||
// notary repository
|
// notary repository
|
||||||
type ErrRepoNotInitialized struct{}
|
type ErrRepoNotInitialized struct{}
|
||||||
|
|
||||||
// ErrRepoNotInitialized is returned when trying to can publish on an uninitialized
|
func (err ErrRepoNotInitialized) Error() string {
|
||||||
// notary repository
|
return "repository has not been initialized"
|
||||||
func (err *ErrRepoNotInitialized) Error() string {
|
|
||||||
return "Repository has not been initialized"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrExpired is returned when the metadata for a role has expired
|
|
||||||
type ErrExpired struct {
|
|
||||||
signed.ErrExpired
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrInvalidRemoteRole is returned when the server is requested to manage
|
// ErrInvalidRemoteRole is returned when the server is requested to manage
|
||||||
|
@ -66,14 +59,21 @@ func (e ErrInvalidRemoteRole) Error() string {
|
||||||
"notary does not support the server managing the %s key", e.Role)
|
"notary does not support the server managing the %s key", e.Role)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrRepositoryNotExist is returned when an action is taken on a remote
|
||||||
|
// repository that doesn't exist
|
||||||
|
type ErrRepositoryNotExist struct {
|
||||||
|
remote string
|
||||||
|
gun string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrRepositoryNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("%s does not have trust data for %s", err.remote, err.gun)
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tufDir = "tuf"
|
tufDir = "tuf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrRepositoryNotExist gets returned when trying to make an action over a repository
|
|
||||||
/// that doesn't exist.
|
|
||||||
var ErrRepositoryNotExist = errors.New("repository does not exist")
|
|
||||||
|
|
||||||
// NotaryRepository stores all the information needed to operate on a notary
|
// NotaryRepository stores all the information needed to operate on a notary
|
||||||
// repository.
|
// repository.
|
||||||
type NotaryRepository struct {
|
type NotaryRepository struct {
|
||||||
|
@ -420,19 +420,11 @@ func (r *NotaryRepository) RemoveTarget(targetName string, roles ...string) erro
|
||||||
// subtree and also the "targets/x" subtree, as we will defer parsing it until
|
// subtree and also the "targets/x" subtree, as we will defer parsing it until
|
||||||
// we explicitly reach it in our iteration of the provided list of roles.
|
// we explicitly reach it in our iteration of the provided list of roles.
|
||||||
func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, error) {
|
func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, error) {
|
||||||
c, err := r.bootstrapClient()
|
_, err := r.Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Update()
|
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(signed.ErrExpired); ok {
|
|
||||||
return nil, ErrExpired{err}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(roles) == 0 {
|
if len(roles) == 0 {
|
||||||
roles = []string{data.CanonicalTargetsRole}
|
roles = []string{data.CanonicalTargetsRole}
|
||||||
}
|
}
|
||||||
|
@ -488,19 +480,11 @@ func (r *NotaryRepository) listSubtree(targets map[string]*TargetWithRole, role
|
||||||
// will be returned
|
// will be returned
|
||||||
// See the IMPORTANT section on ListTargets above. Those roles also apply here.
|
// See the IMPORTANT section on ListTargets above. Those roles also apply here.
|
||||||
func (r *NotaryRepository) GetTargetByName(name string, roles ...string) (*TargetWithRole, error) {
|
func (r *NotaryRepository) GetTargetByName(name string, roles ...string) (*TargetWithRole, error) {
|
||||||
c, err := r.bootstrapClient()
|
c, err := r.Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Update()
|
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(signed.ErrExpired); ok {
|
|
||||||
return nil, ErrExpired{err}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(roles) == 0 {
|
if len(roles) == 0 {
|
||||||
roles = append(roles, data.CanonicalTargetsRole)
|
roles = append(roles, data.CanonicalTargetsRole)
|
||||||
}
|
}
|
||||||
|
@ -530,47 +514,33 @@ func (r *NotaryRepository) GetChangelist() (changelist.Changelist, error) {
|
||||||
// Conceptually it performs an operation similar to a `git rebase`
|
// Conceptually it performs an operation similar to a `git rebase`
|
||||||
func (r *NotaryRepository) Publish() error {
|
func (r *NotaryRepository) Publish() error {
|
||||||
var initialPublish bool
|
var initialPublish bool
|
||||||
// attempt to initialize the repo from the remote store
|
// update first before publishing
|
||||||
c, err := r.bootstrapClient()
|
_, err := r.Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(store.ErrMetaNotFound); ok {
|
// If the remote is not aware of the repo, then this is being published
|
||||||
// if the remote store return a 404 (translated into ErrMetaNotFound),
|
// for the first time. Try to load from disk instead for publishing.
|
||||||
// there is no trust data for yet. Attempt to load it from disk.
|
if _, ok := err.(ErrRepositoryNotExist); ok {
|
||||||
err := r.bootstrapRepo()
|
err := r.bootstrapRepo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// There are lots of reasons there might be an error, such as
|
|
||||||
// corrupt metadata. We need better errors from bootstrapRepo.
|
|
||||||
logrus.Debugf("Unable to load repository from local files: %s",
|
logrus.Debugf("Unable to load repository from local files: %s",
|
||||||
err.Error())
|
err.Error())
|
||||||
if _, ok := err.(store.ErrMetaNotFound); ok {
|
if _, ok := err.(store.ErrMetaNotFound); ok {
|
||||||
return &ErrRepoNotInitialized{}
|
return ErrRepoNotInitialized{}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// We had local data but the server doesn't know about the repo yet,
|
// Ensure we will push the initial root and targets file. Either or
|
||||||
// ensure we will push the initial root and targets file. Either or
|
|
||||||
// both of the root and targets may not be marked as Dirty, since
|
// both of the root and targets may not be marked as Dirty, since
|
||||||
// there may not be any changes that update them, so use a
|
// there may not be any changes that update them, so use a
|
||||||
// different boolean.
|
// different boolean.
|
||||||
initialPublish = true
|
initialPublish = true
|
||||||
} else {
|
} else {
|
||||||
// The remote store returned an error other than 404. We're
|
// We could not update, so we cannot publish.
|
||||||
// unable to determine if the repo has been initialized or not.
|
|
||||||
logrus.Error("Could not publish Repository: ", err.Error())
|
logrus.Error("Could not publish Repository: ", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// If we were successfully able to bootstrap the client (which only pulls
|
|
||||||
// root.json), update it with the rest of the tuf metadata in
|
|
||||||
// preparation for applying the changelist.
|
|
||||||
err = c.Update()
|
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(signed.ErrExpired); ok {
|
|
||||||
return ErrExpired{err}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cl, err := r.GetChangelist()
|
cl, err := r.GetChangelist()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -745,6 +715,28 @@ func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error {
|
||||||
return r.fileStore.SetMeta(data.CanonicalSnapshotRole, snapshotJSON)
|
return r.fileStore.SetMeta(data.CanonicalSnapshotRole, snapshotJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update bootstraps a trust anchor (root.json) before updating all the
|
||||||
|
// metadata from the repo.
|
||||||
|
func (r *NotaryRepository) Update() (*tufclient.Client, error) {
|
||||||
|
c, err := r.bootstrapClient()
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(store.ErrMetaNotFound); ok {
|
||||||
|
host := r.baseURL
|
||||||
|
parsed, err := url.Parse(r.baseURL)
|
||||||
|
if err == nil {
|
||||||
|
host = parsed.Host // try to exclude the scheme and any paths
|
||||||
|
}
|
||||||
|
return nil, ErrRepositoryNotExist{remote: host, gun: r.gun}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = c.Update()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) {
|
func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) {
|
||||||
var rootJSON []byte
|
var rootJSON []byte
|
||||||
remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
|
remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
|
||||||
|
|
|
@ -1516,7 +1516,7 @@ func TestNotInitializedOnPublish(t *testing.T) {
|
||||||
|
|
||||||
err = repo.Publish()
|
err = repo.Publish()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.IsType(t, &ErrRepoNotInitialized{}, err)
|
require.IsType(t, ErrRepoNotInitialized{}, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type cannotCreateKeys struct {
|
type cannotCreateKeys struct {
|
||||||
|
|
Loading…
Reference in New Issue