Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactoring harbor satellite and fixing test cases. #44

Merged
merged 10 commits into from
Sep 20, 2024
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ dist/
.DS_Store
zot/cache.db
secrets.txt
__debug_bin1949266242
13 changes: 11 additions & 2 deletions ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,23 @@ To run a particular function, run:
To build the satellite binaries, use the following command:
- ```sh
dagger call build --source=. --name=satellite export --path=./bin
This would spin up a container and install required dependencies and build various architecture binaries and export them to the host on path ./bin for testing on the host.
This would spin up a container and install required dependencies and build various architecture binaries and export them to the host on path ./bin for testing on the host.
- #### Example: Releasing to GitHub
To release the project on GitHub, use the following command
- ```sh
dagger call release --directory=. --token=<your_github_token> --name=satellite
The above function would then proceed to release the project on github for the name provided. The above function also takes argument `--release-type` which would tell the release what kind of release it is i.e major, minor or path, The default value is set to be path release
The above function would then proceed to release the project on github for the name provided. The above function also takes argument `--release-type` which would tell the release what kind of release it is i.e major, minor or path, The default value is set to be path release
- #### Example: Releasing to GitHub with type of release
To release the project on GitHub, use the following command
- ```sh
dagger call release --directory=. --token=<your_github_token> --name=satellite --release-type=minor
The above function would release the minor version for the project mentioned
- #### Example: Running test cases using dagger
To run the test cases using dagger use the following command
- ```sh
dagger run go test ./... -v -count=1
This would run the test cases present in the entire project.
To run the test cases without dagger use the following command
- ```sh
go test ./... -v -count=1 -args -abs=false
This would set the config file to use the relative path.
132 changes: 132 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package config

import (
"fmt"

"github.com/spf13/viper"
)

var AppConfig *Config

type Config struct {
logLevel string
ownRegistry bool
ownRegistryAdr string
ownRegistryPort string
zotConfigPath string
input string
zot_url string
registry string
repository string
user_input string
scheme string
api_version string
image string
Mehul-Kumar-27 marked this conversation as resolved.
Show resolved Hide resolved
}

func GetLogLevel() string {
return AppConfig.logLevel
}

func GetOwnRegistry() bool {
return AppConfig.ownRegistry
}

func GetOwnRegistryAdr() string {
return AppConfig.ownRegistryAdr
}

func GetOwnRegistryPort() string {
return AppConfig.ownRegistryPort
}

func GetZotConfigPath() string {
return AppConfig.zotConfigPath
}

func GetInput() string {
return AppConfig.input
}

func SetZotURL(url string) {
AppConfig.zot_url = url
}

func GetZotURL() string {
return AppConfig.zot_url
}

func SetRegistry(registry string) {
AppConfig.registry = registry
}

func GetRegistry() string {
return AppConfig.registry
}

func SetRepository(repository string) {
AppConfig.repository = repository
}

func GetRepository() string {
return AppConfig.repository
}

func SetUserInput(user_input string) {
AppConfig.user_input = user_input
}

func GetUserInput() string {
return AppConfig.user_input
}

func SetScheme(scheme string) {
AppConfig.scheme = scheme
}

func GetScheme() string {
return AppConfig.scheme
}

func SetAPIVersion(api_version string) {
AppConfig.api_version = api_version
}

func GetAPIVersion() string {
return AppConfig.api_version
}

func SetImage(image string) {
AppConfig.image = image
}

func GetImage() string {
return AppConfig.image
}

func LoadConfig() (*Config, error) {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
if err := viper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("error reading config file: %w", err)
Mehul-Kumar-27 marked this conversation as resolved.
Show resolved Hide resolved
}

return &Config{
logLevel: viper.GetString("log_level"),
ownRegistry: viper.GetBool("bring_own_registry"),
ownRegistryAdr: viper.GetString("own_registry_adr"),
ownRegistryPort: viper.GetString("own_registry_port"),
zotConfigPath: viper.GetString("zotConfigPath"),
input: viper.GetString("url_or_file"),
}, nil
}

func InitConfig() error {
var err error
AppConfig, err = LoadConfig()
if err != nil {
return err
}
return nil
}
11 changes: 11 additions & 0 deletions internal/images/get-images.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ import (
"time"
)

type ImageList struct {
RegistryURL string `json:"registryUrl"`
Repositories []struct {
Repository string `json:"repository"`
Images []struct {
Name string `json:"name"`
} `json:"images"`
} `json:"repositories"`
}


type Image struct {
ID int `json:"ID"`
Registry string `json:"Registry"`
Expand Down
34 changes: 34 additions & 0 deletions internal/satellite/routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package satellite

import (
"encoding/json"
"net/http"

"container-registry.com/harbor-satellite/internal/server"
)

type SatelliteRegistrar struct{}

type SatelliteResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
StatusCode int `json:"status_code"`
}

func (sr *SatelliteRegistrar) RegisterRoutes(router server.Router) {
satelliteGroup := router.Group("/satellite")
satelliteGroup.HandleFunc("/ping", sr.Ping)
}

func (sr *SatelliteRegistrar) Ping(w http.ResponseWriter, r *http.Request) {
response := SatelliteResponse{
Success: true,
Message: "Ping satellite successful",
StatusCode: http.StatusOK,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
28 changes: 28 additions & 0 deletions internal/server/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package server

import (
"log"
"net/http"
"time"
)

type Middleware func(http.Handler) http.Handler

// LoggingMiddleware creates a new logging middleware
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()

// Call the next handler
next.ServeHTTP(w, r)

// Log the request
log.Printf(
"%s %s %s %s",
r.RemoteAddr,
r.Method,
r.URL.Path,
time.Since(start),
)
})
}
Mehul-Kumar-27 marked this conversation as resolved.
Show resolved Hide resolved
30 changes: 30 additions & 0 deletions internal/server/profiling.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package server

import (
"net/http/pprof"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

type MetricsRegistrar struct{}

type DebugRegistrar struct{}

func (m *MetricsRegistrar) RegisterRoutes(router Router) {
metricsGroup := router.Group("/metrics")
metricsGroup.Handle("", promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{}))
}

func (dr *DebugRegistrar) RegisterRoutes(router Router) {
debugGroup := router.Group("/debug/pprof")
debugGroup.HandleFunc("/", pprof.Index)
debugGroup.HandleFunc("/profile", pprof.Profile)
debugGroup.HandleFunc("/trace", pprof.Trace)
debugGroup.HandleFunc("/symbol", pprof.Symbol)
debugGroup.Handle("/heap", pprof.Handler("heap"))
debugGroup.Handle("/goroutine", pprof.Handler("goroutine"))
debugGroup.Handle("/threadcreate", pprof.Handler("threadcreate"))
debugGroup.Handle("/block", pprof.Handler("block"))
debugGroup.Handle("/mutex", pprof.Handler("mutex"))
}
66 changes: 66 additions & 0 deletions internal/server/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package server

import "net/http"

type Router interface {
// Handle registers a new route with the given pattern and handler on the router mux
Handle(pattern string, handler http.Handler)
// HandleFunc registers a new route with the given pattern and handler function on the router mux
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
// ServeHTTP would dispatch the request to the default mux
ServeHTTP(w http.ResponseWriter, r *http.Request)
// Use adds middleware to the default router
Use(middleware ...Middleware)
// Group called on the router would create a group with the given prefix
//and would inherit the middleware from the router and would be added to the root group of the router
Group(prefix string) *RouterGroup
}

type Endpoint struct {
Method string
Path string
}
// DefaultRouter
type DefaultRouter struct {
// mux is the default http.ServeMux
mux *http.ServeMux
// middleware is the list of middleware to be applied to default router and all groups inside it
middleware []Middleware
// rootGroup is the root RouterGroup
rootGroup *RouterGroup
// endpoints is the list of all registered endpoints
Endpoints []Endpoint
}

// NewDefaultRouter creates a new DefaultRouter with the given prefix
func NewDefaultRouter(prefix string) *DefaultRouter {
dr := &DefaultRouter{mux: http.NewServeMux()}
dr.rootGroup = &RouterGroup{prefix: prefix, router: dr}
return dr
}


func (r *DefaultRouter) Handle(pattern string, handler http.Handler) {
r.mux.Handle(pattern, handler)
}


func (r *DefaultRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
r.mux.ServeHTTP(w, req)
}


func (dr *DefaultRouter) HandleFunc(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) {
dr.Handle(pattern, http.HandlerFunc(handlerFunc))
}


func (dr *DefaultRouter) Use(middleware ...Middleware) {
dr.middleware = append(dr.middleware, middleware...)
}


// Group creates a new RouterGroup under the rootGroup with the given prefix
func (dr *DefaultRouter) Group(prefix string) *RouterGroup {
return dr.rootGroup.Group(prefix)
}
36 changes: 36 additions & 0 deletions internal/server/router_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

package server

import "net/http"

// RouterGroup represents a group of routes with a common prefix and middleware
type RouterGroup struct {
prefix string
middleware []Middleware
router Router
}

func (rg *RouterGroup) Use(middleware ...Middleware) {
rg.middleware = append(rg.middleware, middleware...)
}

func (rg *RouterGroup) Handle(pattern string, handler http.Handler) {
fullPattern := rg.prefix + pattern
wrappedHandler := handler
for i := len(rg.middleware) - 1; i >= 0; i-- {
wrappedHandler = rg.middleware[i](wrappedHandler)
}
rg.router.Handle(fullPattern, wrappedHandler)
}

func (rg *RouterGroup) HandleFunc(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) {
rg.Handle(pattern, http.HandlerFunc(handlerFunc))
}

func (rg *RouterGroup) Group(prefix string) *RouterGroup {
return &RouterGroup{
prefix: rg.prefix + prefix,
middleware: append([]Middleware{}, rg.middleware...),
router: rg.router,
}
}
Mehul-Kumar-27 marked this conversation as resolved.
Show resolved Hide resolved
Loading