Skip to content

Commit

Permalink
update group deletion and image list
Browse files Browse the repository at this point in the history
Signed-off-by: bupd <[email protected]>
  • Loading branch information
bupd committed Sep 9, 2024
1 parent 1c76c9d commit 031ef53
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 27 deletions.
10 changes: 10 additions & 0 deletions ground-control/internal/database/groups.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions ground-control/internal/database/images.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

144 changes: 125 additions & 19 deletions ground-control/internal/server/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"time"

"container-registry.com/harbor-satellite/ground-control/internal/database"
"container-registry.com/harbor-satellite/ground-control/internal/utils"
"container-registry.com/harbor-satellite/ground-control/reg"
"github.com/gorilla/mux"
)
Expand Down Expand Up @@ -55,10 +56,7 @@ type AssignImageToSatelliteParams struct {
ImageID int32 `json:"image_id"`
}
type ImageAddParams struct {
Registry string `json:"registry"`
Repository string `json:"repository"`
Tag string `json:"tag"`
Digest string `json:"digest"`
Image string `json:"image"`
}

func DecodeRequestBody(r *http.Request, v interface{}) error {
Expand Down Expand Up @@ -126,6 +124,33 @@ func (s *Server) createGroupHandler(w http.ResponseWriter, r *http.Request) {
WriteJSONResponse(w, http.StatusCreated, result)
}

func (s *Server) deleteGroupHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
groupID := vars["groupID"]

id, err := strconv.ParseInt(groupID, 10, 32)
if err != nil {
err = &AppError{
Message: "Error: Invalid groupID",
Code: http.StatusBadRequest,
}
HandleAppError(w, err)
return
}

err = s.dbQueries.DeleteGroup(r.Context(), int32(id))
if err != nil {
err = &AppError{
Message: err.Error(),
Code: http.StatusBadRequest,
}
HandleAppError(w, err)
return
}

WriteJSONResponse(w, http.StatusOK, map[string]string{})
}

func (s *Server) createLabelHandler(w http.ResponseWriter, r *http.Request) {
var req LabelRequestParams
if err := DecodeRequestBody(r, &req); err != nil {
Expand All @@ -150,29 +175,80 @@ func (s *Server) createLabelHandler(w http.ResponseWriter, r *http.Request) {
func (s *Server) addImageHandler(w http.ResponseWriter, r *http.Request) {
var req ImageAddParams
if err := DecodeRequestBody(r, &req); err != nil {
log.Println(err)
HandleAppError(w, err)
return
}

image, err := utils.ParseArtifactURL(req.Image)
if err != nil {
log.Println(err)
err = &AppError{
Message: "Error: Invalid Artifact URL",
Code: http.StatusBadRequest,
}
HandleAppError(w, err)
return
}

params := database.AddImageParams{
Registry: req.Registry,
Repository: req.Repository,
Tag: req.Tag,
Digest: req.Digest,
Registry: image.Registry,
Repository: image.Repository,
Tag: image.Tag,
Digest: image.Digest,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}

// Call the database query to create Group
// Call the database query to add image
result, err := s.dbQueries.AddImage(r.Context(), params)
if err != nil {
log.Println(err)
err = &AppError{
Message: "Error: Invalid Artifact URL",
Code: http.StatusBadRequest,
}
HandleAppError(w, err)
return
}

WriteJSONResponse(w, http.StatusCreated, result)
}

func (s *Server) listImageHandler(w http.ResponseWriter, r *http.Request) {
result, err := s.dbQueries.ListImages(r.Context())
if err != nil {
err = fmt.Errorf("error: list images failed: %v", err)
log.Println(err)
HandleAppError(w, err)
return
}

WriteJSONResponse(w, http.StatusOK, result)
}

func (s *Server) removeImageHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
imageID := vars["imageID"]

id, err := strconv.ParseInt(imageID, 10, 32)
if err != nil {
err = fmt.Errorf("error: invalid imageID: %v", err)
log.Println(err)
HandleAppError(w, err)
return
}

err = s.dbQueries.DeleteImage(r.Context(), int32(id))
if err != nil {
err = fmt.Errorf("error: delete image failed: %v", err)
log.Println(err)
HandleAppError(w, err)
return
}
WriteJSONResponse(w, http.StatusOK, map[string]string{})
}

func (s *Server) addSatelliteHandler(w http.ResponseWriter, r *http.Request) {
var req AddSatelliteParams
if err := DecodeRequestBody(r, &req); err != nil {
Expand Down Expand Up @@ -242,9 +318,14 @@ func (s *Server) deleteSatelliteByID(w http.ResponseWriter, r *http.Request) {
return
}

result := s.dbQueries.DeleteSatellite(r.Context(), int32(id))
err = s.dbQueries.DeleteSatellite(r.Context(), int32(id))
if err != nil {
log.Printf("error: delete satellite failed: %v", err)
HandleAppError(w, err)
return
}

WriteJSONResponse(w, http.StatusOK, result)
WriteJSONResponse(w, http.StatusOK, map[string]string{})
}

func (s *Server) assignImageToSatellite(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -477,6 +558,31 @@ func (s *Server) deleteImageFromGroup(w http.ResponseWriter, r *http.Request) {
WriteJSONResponse(w, http.StatusOK, map[string]string{})
}

func (s *Server) listGroupImages(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
groupID := vars["groupID"]

id, err := strconv.ParseInt(groupID, 10, 32)
if err != nil {
log.Printf("Error: Invalid groupID: %v", err)
err := &AppError{
Message: "Error: Invalid GroupID",
Code: http.StatusBadRequest,
}
HandleAppError(w, err)
return
}

result, err := s.dbQueries.GetImagesForGroup(r.Context(), int32(id))
if err != nil {
log.Printf("Error: Failed to get image for group: %v", err)
HandleAppError(w, err)
return
}

WriteJSONResponse(w, http.StatusOK, result)
}

func (s *Server) deleteImageFromLabel(w http.ResponseWriter, r *http.Request) {
var req AssignImageToLabelParams
if err := DecodeRequestBody(r, &req); err != nil {
Expand Down Expand Up @@ -563,11 +669,11 @@ func (s *Server) createSatelliteArtifact(ctx context.Context, id int32) error {
images = append(images, image)
}

var groupsState []string
for _, group := range groups {
group := fmt.Sprintf("%s/satellite/groups/%s", url, group)
groupsState = append(groupsState, group)
}
var groupsState []string
for _, group := range groups {
group := fmt.Sprintf("%s/satellite/groups/%s", url, group)
groupsState = append(groupsState, group)
}

State := &reg.SatelliteState{
Name: satellite.Name,
Expand Down Expand Up @@ -634,11 +740,11 @@ func (s *Server) createGroupArtifact(ctx context.Context, groupID int32) error {

func (s *Server) getGroupHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
groupID := vars["group"]
groupID := vars["groupID"]

id, err := strconv.ParseInt(groupID, 10, 32)
id, err := strconv.ParseInt(groupID, 10, 32)
if err != nil {
log.Printf("error: invalid groupID: %v", err)
log.Printf("error: invalid groupID: %v", err)
http.Error(w, err.Error(), http.StatusNotFound)
return
}
Expand Down
20 changes: 12 additions & 8 deletions ground-control/internal/server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,35 @@ func (s *Server) RegisterRoutes() http.Handler {
r.HandleFunc("/ping", s.Ping).Methods("GET")
r.HandleFunc("/health", s.healthHandler).Methods("GET")

r.HandleFunc("/registry/list", s.regListHandler).Methods("GET")
r.HandleFunc("/repos/list", s.regListHandler).Methods("GET")

r.HandleFunc("/image", s.addImageHandler).Methods("POST")
r.HandleFunc("/images", s.addImageHandler).Methods("POST")
r.HandleFunc("/images/list", s.listImageHandler).Methods("GET")
r.HandleFunc("/images/{imageID}", s.removeImageHandler).Methods("DELETE")

// Ground Control interface
r.HandleFunc("/groups/create", s.createGroupHandler).Methods("POST")
r.HandleFunc("/groups", s.createGroupHandler).Methods("POST")
r.HandleFunc("/groups/{groupID}", s.deleteGroupHandler).Methods("DELETE")
r.HandleFunc("/groups/list", s.listGroupHandler).Methods("GET")
r.HandleFunc("/groups/{group}", s.getGroupHandler).Methods("GET")
r.HandleFunc("/groups/{groupID}", s.getGroupHandler).Methods("GET")
r.HandleFunc("/groups/images", s.assignImageToGroup).Methods("POST")
r.HandleFunc("/groups/images", s.deleteImageFromGroup).Methods("DELETE")
r.HandleFunc("/groups/{groupID}/images", s.listGroupImages).Methods("GET")
r.HandleFunc("/groups/satellite", s.addSatelliteToGroup).Methods("POST")
r.HandleFunc("/groups/satellite", s.removeSatelliteFromGroup).Methods("DELETE")

r.HandleFunc("/label", s.createLabelHandler).Methods("POST")
r.HandleFunc("/label/images", s.assignImageToLabel).Methods("POST")
r.HandleFunc("/label/images", s.deleteImageFromLabel).Methods("DELETE")
r.HandleFunc("/label/image", s.assignImageToLabel).Methods("POST")
r.HandleFunc("/label/image", s.deleteImageFromLabel).Methods("DELETE")
r.HandleFunc("/label/satellite", s.addSatelliteToLabel).Methods("POST")

r.HandleFunc("/satellites/create", s.addSatelliteHandler).Methods("POST")
r.HandleFunc("/satellites/list", s.listSatelliteHandler).Methods("GET")
r.HandleFunc("/satellites/{satellite}", s.getSatelliteByID).Methods("GET")
r.HandleFunc("/satellites/{satellite}", s.deleteSatelliteByID).Methods("DELETE")
// r.HandleFunc("/satellites/images", s.GetImagesForSatellite).Methods("GET")
r.HandleFunc("/satellites/images", s.assignImageToSatellite).Methods("POST")
r.HandleFunc("/satellites/images", s.removeImageFromSatellite).Methods("DELETE")
r.HandleFunc("/satellites/image", s.assignImageToSatellite).Methods("POST")
r.HandleFunc("/satellites/image", s.removeImageFromSatellite).Methods("DELETE")

// Satellite based routes
// r.HandleFunc("/images", s.getImageListHandler).Methods("GET")
Expand Down
74 changes: 74 additions & 0 deletions ground-control/internal/utils/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package utils

import (
"fmt"
"log"
"net/url"
"strings"

"container-registry.com/harbor-satellite/ground-control/reg"
)

// ParseArtifactURL parses an artifact URL and returns a reg.Images struct
func ParseArtifactURL(rawURL string) (reg.Images, error) {
// Add "https://" scheme if missing
if !strings.Contains(rawURL, "://") {
rawURL = "https://" + rawURL
}

// Parse the URL
parsedURL, err := url.Parse(rawURL)
if err != nil {
return reg.Images{}, fmt.Errorf("error: invalid URL: %s", err)
}

// Extract registry (host) and repo path
registry := parsedURL.Host
path := strings.TrimPrefix(parsedURL.Path, "/")

// Split the repo, tag, and digest
repo, tag, digest := splitRepoTagDigest(path)

// Validate that repository and registry exist
if repo == "" || registry == "" {
log.Println("Error: Missing repository or registry.")
return reg.Images{}, fmt.Errorf("error: missing repository or registry in URL: %s", rawURL)
}

// Validate that either tag or digest exists
if tag == "" && digest == "" {
log.Println("Error: Missing tag or digest.")
return reg.Images{}, fmt.Errorf("error: missing tag or digest in artifact URL: %s", rawURL)
}

// Return a populated reg.Images struct
return reg.Images{
Registry: registry,
Repository: repo,
Tag: tag,
Digest: digest,
}, nil
}

// Helper function to split repo, tag, and digest from the path
func splitRepoTagDigest(path string) (string, string, string) {
var repo, tag, digest string

// First, split based on '@' to separate digest
if strings.Contains(path, "@") {
parts := strings.Split(path, "@")
repo = parts[0]
digest = parts[1]
} else {
repo = path
}

// Next, split repo and tag based on ':'
if strings.Contains(repo, ":") {
parts := strings.Split(repo, ":")
repo = parts[0]
tag = parts[1]
}

return repo, tag, digest
}
Loading

0 comments on commit 031ef53

Please sign in to comment.