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 (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"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
|
||||
type ErrRepoNotInitialized struct{}
|
||||
|
||||
// ErrRepoNotInitialized is returned when trying to can publish on an uninitialized
|
||||
// notary repository
|
||||
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
|
||||
func (err ErrRepoNotInitialized) Error() string {
|
||||
return "repository has not been initialized"
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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 (
|
||||
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
|
||||
// repository.
|
||||
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
|
||||
// we explicitly reach it in our iteration of the provided list of roles.
|
||||
func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, error) {
|
||||
c, err := r.bootstrapClient()
|
||||
_, err := r.Update()
|
||||
if err != nil {
|
||||
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 {
|
||||
roles = []string{data.CanonicalTargetsRole}
|
||||
}
|
||||
|
@ -488,19 +480,11 @@ func (r *NotaryRepository) listSubtree(targets map[string]*TargetWithRole, role
|
|||
// will be returned
|
||||
// See the IMPORTANT section on ListTargets above. Those roles also apply here.
|
||||
func (r *NotaryRepository) GetTargetByName(name string, roles ...string) (*TargetWithRole, error) {
|
||||
c, err := r.bootstrapClient()
|
||||
c, err := r.Update()
|
||||
if err != nil {
|
||||
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 {
|
||||
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`
|
||||
func (r *NotaryRepository) Publish() error {
|
||||
var initialPublish bool
|
||||
// attempt to initialize the repo from the remote store
|
||||
c, err := r.bootstrapClient()
|
||||
// update first before publishing
|
||||
_, err := r.Update()
|
||||
if err != nil {
|
||||
if _, ok := err.(store.ErrMetaNotFound); ok {
|
||||
// if the remote store return a 404 (translated into ErrMetaNotFound),
|
||||
// there is no trust data for yet. Attempt to load it from disk.
|
||||
// If the remote is not aware of the repo, then this is being published
|
||||
// for the first time. Try to load from disk instead for publishing.
|
||||
if _, ok := err.(ErrRepositoryNotExist); ok {
|
||||
err := r.bootstrapRepo()
|
||||
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",
|
||||
err.Error())
|
||||
if _, ok := err.(store.ErrMetaNotFound); ok {
|
||||
return &ErrRepoNotInitialized{}
|
||||
return ErrRepoNotInitialized{}
|
||||
}
|
||||
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
|
||||
// there may not be any changes that update them, so use a
|
||||
// different boolean.
|
||||
initialPublish = true
|
||||
} else {
|
||||
// The remote store returned an error other than 404. We're
|
||||
// unable to determine if the repo has been initialized or not.
|
||||
// We could not update, so we cannot publish.
|
||||
logrus.Error("Could not publish Repository: ", err.Error())
|
||||
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()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -745,6 +715,28 @@ func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error {
|
|||
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) {
|
||||
var rootJSON []byte
|
||||
remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
|
||||
|
|
|
@ -1516,7 +1516,7 @@ func TestNotInitializedOnPublish(t *testing.T) {
|
|||
|
||||
err = repo.Publish()
|
||||
require.Error(t, err)
|
||||
require.IsType(t, &ErrRepoNotInitialized{}, err)
|
||||
require.IsType(t, ErrRepoNotInitialized{}, err)
|
||||
}
|
||||
|
||||
type cannotCreateKeys struct {
|
||||
|
|
Loading…
Reference in New Issue