adding delete to server

Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
David Lawrence 2015-06-21 16:37:30 -07:00
parent b0ee6f0c4e
commit 0f1e8b0134
3 changed files with 46 additions and 14 deletions

View File

@ -33,7 +33,7 @@ func MainHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *e
return nil return nil
} }
// AddHandler accepts urls in the form /<imagename>/<tag> // AddHandler adds the provided json data for the role and GUN specified in the URL
func UpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *errors.HTTPError { func UpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
defer r.Body.Close() defer r.Body.Close()
s := ctx.Value("versionStore") s := ctx.Value("versionStore")
@ -84,7 +84,7 @@ func UpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
return nil return nil
} }
// GetHandler accepts urls in the form /<imagename>/<tuf file>.json // GetHandler returns the json for a specified role and GUN.
func GetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *errors.HTTPError { func GetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
s := ctx.Value("versionStore") s := ctx.Value("versionStore")
store, ok := s.(*storage.MySQLStorage) store, ok := s.(*storage.MySQLStorage)
@ -120,3 +120,28 @@ func GetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *er
w.Write(data) w.Write(data)
return nil return nil
} }
// DeleteHandler deletes all data for a GUN. A 200 responses indicates success.
func DeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
s := ctx.Value("versionStore")
store, ok := s.(*storage.MySQLStorage)
if !ok {
return &errors.HTTPError{
HTTPStatus: http.StatusInternalServerError,
Code: 9999,
Err: fmt.Errorf("Version store not configured"),
}
}
vars := mux.Vars(r)
gun := vars["imageName"]
err := store.Delete(gun)
if err != nil {
logrus.Errorf("[Notary Server] 500 DELETE repository: %s", gun)
return &errors.HTTPError{
HTTPStatus: http.StatusInternalServerError,
Code: 9999,
Err: err,
}
}
return nil
}

View File

@ -107,6 +107,7 @@ func run(ctx context.Context, addr, tlsCertFile, tlsKeyFile string, trust signed
// TODO (endophage): use correct regexes for image and tag names // TODO (endophage): use correct regexes for image and tag names
r.Methods("GET").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:(root|targets|timestamp|snapshot)}.json").Handler(hand(handlers.GetHandler, "pull")) r.Methods("GET").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:(root|targets|timestamp|snapshot)}.json").Handler(hand(handlers.GetHandler, "pull"))
r.Methods("POST").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:(root|targets|timestamp|snapshot)}.json").Handler(hand(handlers.UpdateHandler, "push", "pull")) r.Methods("POST").Path("/v2/{imageName:.*}/_trust/tuf/{tufRole:(root|targets|timestamp|snapshot)}.json").Handler(hand(handlers.UpdateHandler, "push", "pull"))
r.Methods("DELETE").Path("/v2/{imageName:.*}/_trust/tuf/").Handler(hand(handlers.DeleteHandler, "push", "pull"))
svr := NewHTTPServer( svr := NewHTTPServer(
http.Server{ http.Server{

View File

@ -9,12 +9,12 @@ import (
// The database table must look like: // The database table must look like:
// CREATE TABLE `tuf_files` ( // CREATE TABLE `tuf_files` (
// `id` INT AUTO_INCREMENT, // `id` INT AUTO_INCREMENT,
// `qdn` VARCHAR(255) NOT NULL // `gun` VARCHAR(255) NOT NULL
// `role` VARCHAR(255) NOT NULL // `role` VARCHAR(255) NOT NULL
// `version` INT // `version` INT
// `data` LONGBLOB // `data` LONGBLOB
// PRIMARY KEY (`id`) // PRIMARY KEY (`id`)
// UNIQUE INDEX (`qdn`, `role`, `version`) // UNIQUE INDEX (`gun`, `role`, `version`)
// ) DEFAULT CHARSET=utf8; // ) DEFAULT CHARSET=utf8;
type MySQLStorage struct { type MySQLStorage struct {
sql.DB sql.DB
@ -28,25 +28,25 @@ func NewMySQLStorage(db *sql.DB) *MySQLStorage {
// Update multiple TUF records in a single transaction. // Update multiple TUF records in a single transaction.
// Always insert a new row. The unique constraint will ensure there is only ever // Always insert a new row. The unique constraint will ensure there is only ever
func (vdb *MySQLStorage) UpdateCurrent(qdn, role string, version int, data []byte) error { func (db *MySQLStorage) UpdateCurrent(gun, role string, version int, data []byte) error {
checkStmt := "SELECT count(*) FROM `tuf_files` WHERE `qdn`=? AND `role`=? AND `version`>=?;" checkStmt := "SELECT count(*) FROM `tuf_files` WHERE `gun`=? AND `role`=? AND `version`>=?;"
insertStmt := "INSERT INTO `tuf_files` (`qdn`, `role`, `version`, `data`) VALUES (?,?,?,?) ;" insertStmt := "INSERT INTO `tuf_files` (`gun`, `role`, `version`, `data`) VALUES (?,?,?,?) ;"
// ensure immediately previous version exists // ensure immediately previous version exists
row := vdb.QueryRow(checkStmt, qdn, role, version) row := db.QueryRow(checkStmt, gun, role, version)
var exists int var exists int
err := row.Scan(&exists) err := row.Scan(&exists)
if err != nil { if err != nil {
return err return err
} }
if exists != 0 { if exists != 0 {
return fmt.Errorf("Attempting to write an old version for QDN: %s, role: %s, version: %d. A newer version is available.", qdn, role, version) return fmt.Errorf("Attempting to write an old version for gun: %s, role: %s, version: %d. A newer version is available.", gun, role, version)
} }
// attempt to insert. Due to race conditions with the check this could fail. // attempt to insert. Due to race conditions with the check this could fail.
// That's OK, we're doing first write wins. The client will be messaged it // That's OK, we're doing first write wins. The client will be messaged it
// needs to rebase. // needs to rebase.
_, err = vdb.Exec(insertStmt, qdn, role, version, data) _, err = db.Exec(insertStmt, gun, role, version, data)
if err != nil { if err != nil {
return err return err
} }
@ -54,14 +54,14 @@ func (vdb *MySQLStorage) UpdateCurrent(qdn, role string, version int, data []byt
} }
// Get a specific TUF record // Get a specific TUF record
func (vdb *MySQLStorage) GetCurrent(qdn, tufRole string) (data []byte, err error) { func (db *MySQLStorage) GetCurrent(gun, tufRole string) (data []byte, err error) {
stmt := "SELECT `data` FROM `tuf_files` WHERE `qdn`=? AND `role`=? ORDER BY `version` DESC LIMIT 1;" stmt := "SELECT `data` FROM `tuf_files` WHERE `gun`=? AND `role`=? ORDER BY `version` DESC LIMIT 1;"
rows, err := vdb.Query(stmt, qdn, tufRole) // this should be a QueryRow() rows, err := db.Query(stmt, gun, tufRole) // this should be a QueryRow()
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer rows.Close() defer rows.Close()
// unique constraint on (qdn, role) will ensure only one row is returned (or none if no match is found) // unique constraint on (gun, role) will ensure only one row is returned (or none if no match is found)
if !rows.Next() { if !rows.Next() {
return nil, nil return nil, nil
} }
@ -72,3 +72,9 @@ func (vdb *MySQLStorage) GetCurrent(qdn, tufRole string) (data []byte, err error
} }
return data, nil return data, nil
} }
func (db *MySQLStorage) Delete(gun string) error {
stmt := "DELETE FROM `tuf_files` WHERE `gun`=?;"
_, err := db.Exec(stmt, gun)
return err
}