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
}
// 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 {
defer r.Body.Close()
s := ctx.Value("versionStore")
@ -84,7 +84,7 @@ func UpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
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 {
s := ctx.Value("versionStore")
store, ok := s.(*storage.MySQLStorage)
@ -120,3 +120,28 @@ func GetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *er
w.Write(data)
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
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("DELETE").Path("/v2/{imageName:.*}/_trust/tuf/").Handler(hand(handlers.DeleteHandler, "push", "pull"))
svr := NewHTTPServer(
http.Server{

View File

@ -9,12 +9,12 @@ import (
// The database table must look like:
// CREATE TABLE `tuf_files` (
// `id` INT AUTO_INCREMENT,
// `qdn` VARCHAR(255) NOT NULL
// `gun` VARCHAR(255) NOT NULL
// `role` VARCHAR(255) NOT NULL
// `version` INT
// `data` LONGBLOB
// PRIMARY KEY (`id`)
// UNIQUE INDEX (`qdn`, `role`, `version`)
// UNIQUE INDEX (`gun`, `role`, `version`)
// ) DEFAULT CHARSET=utf8;
type MySQLStorage struct {
sql.DB
@ -28,25 +28,25 @@ func NewMySQLStorage(db *sql.DB) *MySQLStorage {
// Update multiple TUF records in a single transaction.
// 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 {
checkStmt := "SELECT count(*) FROM `tuf_files` WHERE `qdn`=? AND `role`=? AND `version`>=?;"
insertStmt := "INSERT INTO `tuf_files` (`qdn`, `role`, `version`, `data`) VALUES (?,?,?,?) ;"
func (db *MySQLStorage) UpdateCurrent(gun, role string, version int, data []byte) error {
checkStmt := "SELECT count(*) FROM `tuf_files` WHERE `gun`=? AND `role`=? AND `version`>=?;"
insertStmt := "INSERT INTO `tuf_files` (`gun`, `role`, `version`, `data`) VALUES (?,?,?,?) ;"
// ensure immediately previous version exists
row := vdb.QueryRow(checkStmt, qdn, role, version)
row := db.QueryRow(checkStmt, gun, role, version)
var exists int
err := row.Scan(&exists)
if err != nil {
return err
}
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.
// That's OK, we're doing first write wins. The client will be messaged it
// needs to rebase.
_, err = vdb.Exec(insertStmt, qdn, role, version, data)
_, err = db.Exec(insertStmt, gun, role, version, data)
if err != nil {
return err
}
@ -54,14 +54,14 @@ func (vdb *MySQLStorage) UpdateCurrent(qdn, role string, version int, data []byt
}
// Get a specific TUF record
func (vdb *MySQLStorage) GetCurrent(qdn, tufRole string) (data []byte, err error) {
stmt := "SELECT `data` FROM `tuf_files` WHERE `qdn`=? AND `role`=? ORDER BY `version` DESC LIMIT 1;"
rows, err := vdb.Query(stmt, qdn, tufRole) // this should be a QueryRow()
func (db *MySQLStorage) GetCurrent(gun, tufRole string) (data []byte, err error) {
stmt := "SELECT `data` FROM `tuf_files` WHERE `gun`=? AND `role`=? ORDER BY `version` DESC LIMIT 1;"
rows, err := db.Query(stmt, gun, tufRole) // this should be a QueryRow()
if err != nil {
return nil, err
}
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() {
return nil, nil
}
@ -72,3 +72,9 @@ func (vdb *MySQLStorage) GetCurrent(qdn, tufRole string) (data []byte, err error
}
return data, nil
}
func (db *MySQLStorage) Delete(gun string) error {
stmt := "DELETE FROM `tuf_files` WHERE `gun`=?;"
_, err := db.Exec(stmt, gun)
return err
}