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
4 changes: 3 additions & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
HARBOR_USERNAME=admin
HARBOR_PASSWORD=Harbor12345
ZOT_URL="127.0.0.1:8585"
TOKEN=""
TOKEN=""
ENV=dev
USE_UNSECURE=true
Mehul-Kumar-27 marked this conversation as resolved.
Show resolved Hide resolved
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.
2 changes: 1 addition & 1 deletion config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ log_level = "info"

# For testing purposes :
# https://demo.goharbor.io/v2/myproject/album-server
# /image-list/images.json
# ./image-list/images.json
178 changes: 178 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package config

import (
"fmt"
"os"

"github.com/joho/godotenv"
"github.com/spf13/viper"
)

var AppConfig *Config

type Config struct {
log_level string
own_registry bool
own_registry_adr string
own_registry_port string
zot_config_path string
input string
zot_url string
registry string
repository string
user_input string
scheme string
api_version string
image string
harbor_password string
harbor_username string
env string
use_unsecure bool
}

func GetLogLevel() string {
return AppConfig.log_level
}

func GetOwnRegistry() bool {
return AppConfig.own_registry
}

func GetOwnRegistryAdr() string {
return AppConfig.own_registry_adr
}

func GetOwnRegistryPort() string {
return AppConfig.own_registry_port
}

func GetZotConfigPath() string {
return AppConfig.zot_config_path
}

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 UseUnsecure() bool {
return AppConfig.use_unsecure
}

func GetHarborPassword() string {
return AppConfig.harbor_password
}

func GetHarborUsername() string {
return AppConfig.harbor_username
}

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 at path '%s': %w", viper.ConfigFileUsed(), err)
}

// Load environment and start satellite
if err := godotenv.Load(); err != nil {
return &Config{}, fmt.Errorf("error loading .env file: %w", err)
}
var use_unsecure bool
if os.Getenv("USE_UNSECURE") == "true" {
use_unsecure = true
} else {
use_unsecure = false
}

return &Config{
log_level: viper.GetString("log_level"),
own_registry: viper.GetBool("bring_own_registry"),
own_registry_adr: viper.GetString("own_registry_adr"),
own_registry_port: viper.GetString("own_registry_port"),
zot_config_path: viper.GetString("zotConfigPath"),
input: viper.GetString("url_or_file"),
harbor_password: os.Getenv("HARBOR_PASSWORD"),
harbor_username: os.Getenv("HARBOR_USERNAME"),
env: os.Getenv("ENV"),
zot_url: os.Getenv("ZOT_URL"),
use_unsecure: use_unsecure,
}, nil
}

func InitConfig() error {
var err error
AppConfig, err = LoadConfig()
if err != nil {
return err
}
/// Print all the configuration
fmt.Println("Configuration:")
fmt.Println("Log Level: ", AppConfig.log_level)
fmt.Println("Own Registry: ", AppConfig.own_registry)
fmt.Println("Own Registry Address: ", AppConfig.own_registry_adr)
fmt.Println("Own Registry Port: ", AppConfig.own_registry_port)
fmt.Println("Zot Config Path: ", AppConfig.zot_config_path)
fmt.Println("Input: ", AppConfig.input)
fmt.Println("Harbor Password: ", AppConfig.harbor_password)
fmt.Println("Harbor Username: ", AppConfig.harbor_username)
fmt.Println("Environment: ", AppConfig.env)
fmt.Println("Use Unsecure: ", AppConfig.use_unsecure)
return nil
}
Mehul-Kumar-27 marked this conversation as resolved.
Show resolved Hide resolved
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
28 changes: 23 additions & 5 deletions internal/replicate/replicate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path/filepath"
"strings"

"container-registry.com/harbor-satellite/internal/config"
"container-registry.com/harbor-satellite/internal/store"
"container-registry.com/harbor-satellite/logger"
"github.com/google/go-containerregistry/pkg/authn"
Expand All @@ -20,7 +21,12 @@ type Replicator interface {
DeleteExtraImages(ctx context.Context, imgs []store.Image) error
}

type BasicReplicator struct{}
type BasicReplicator struct {
username string
password string
use_unsecure bool
zot_url string
}

type ImageInfo struct {
Name string `json:"name"`
Expand All @@ -37,7 +43,12 @@ type RegistryInfo struct {
}

func NewReplicator(context context.Context) Replicator {
return &BasicReplicator{}
return &BasicReplicator{
username: config.GetHarborUsername(),
password: config.GetHarborPassword(),
use_unsecure: config.UseUnsecure(),
zot_url: config.GetZotURL(),
}
}

func (r *BasicReplicator) Replicate(ctx context.Context, image string) error {
Expand Down Expand Up @@ -177,9 +188,12 @@ func CopyImage(ctx context.Context, imageName string) error {
Username: username,
Password: password,
})

options := []crane.Option{crane.WithAuth(auth)}
if config.UseUnsecure() {
options = append(options, crane.Insecure)
}
// Pull the image with authentication
srcImage, err := crane.Pull(imageName, crane.WithAuth(auth), crane.Insecure)
srcImage, err := crane.Pull(imageName, options...)
if err != nil {
log.Error().Msgf("Failed to pull image: %v", err)
return fmt.Errorf("failed to pull image: %w", err)
Expand All @@ -188,7 +202,11 @@ func CopyImage(ctx context.Context, imageName string) error {
}

// Push the image to the destination registry
err = crane.Push(srcImage, destRef, crane.Insecure)
push_options := []crane.Option{}
if config.UseUnsecure() {
push_options = append(push_options, crane.Insecure)
}
err = crane.Push(srcImage, destRef, push_options...)
if err != nil {
log.Error().Msgf("Failed to push image: %v", err)
return fmt.Errorf("failed to push image: %w", err)
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)
}
}
29 changes: 29 additions & 0 deletions internal/server/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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 %s",
r.RemoteAddr,
r.Method,
r.URL.Path,
r.Response.Status,
time.Since(start),
)
})
}
Loading