Skip to content

Commit b0304ff

Browse files
adding state artifact fetcher to fetch the state from harbor
1 parent aaa9653 commit b0304ff

File tree

7 files changed

+276
-32
lines changed

7 files changed

+276
-32
lines changed

.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ ZOT_URL="127.0.0.1:8585"
44
TOKEN=""
55
ENV=dev
66
USE_UNSECURE=true
7+
GROUP_NAME=test-satellite-group
8+
STATE_ARTIFACT_NAME=state-artifact

ci/utils.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ func (m *HarborSatellite) Service(
5959
}
6060

6161
// Would build the project with the source provided. The name should be the name of the project.
62-
func (m *HarborSatellite) build(source *dagger.Directory, name string) *dagger.Directory {
63-
fmt.Printf("Building %s\n", name)
62+
func (m *HarborSatellite) build(source *dagger.Directory, component string) *dagger.Directory {
63+
fmt.Printf("Building %s\n", component)
6464

6565
gooses := []string{"linux", "darwin"}
6666
goarches := []string{"amd64", "arm64"}

config.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ own_registry_adr = "127.0.0.1"
66
own_registry_port = "8585"
77

88
# URL of remote registry OR local file path
9-
url_or_file = "https://demo.goharbor.io/v2/myproject/album-server"
9+
# url_or_file = "https://demo.goharbor.io/v2/myproject/album-server"
10+
url_or_file = "https://demo.goharbor.io"
1011

1112
# Default path for Zot registry config.json
1213
zotConfigPath = "./registry/config.json"

internal/config/artifact.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package config
2+
3+
// ArtifactReader defines an interface for reading artifact data
4+
type ArtifactReader interface {
5+
// GetRepository returns the repository of the artifact
6+
GetRepository() string
7+
// GetTag returns the tag of the artifact
8+
GetTag() string
9+
// GetHash returns the hash of the artifact
10+
GetHash() string
11+
}
12+
13+
// Artifact represents an artifact object in the registry
14+
type Artifact struct {
15+
Repository string `json:"repository"`
16+
Tag string `json:"tag"`
17+
Hash string `json:"hash"`
18+
}
19+
20+
func NewArtifact() ArtifactReader {
21+
return &Artifact{}
22+
}
23+
24+
func (a *Artifact) GetRepository() string {
25+
return a.Repository
26+
}
27+
28+
func (a *Artifact) GetTag() string {
29+
return a.Tag
30+
}
31+
32+
func (a *Artifact) GetHash() string {
33+
return a.Hash
34+
}

internal/config/config.go

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,26 @@ import (
1111
var AppConfig *Config
1212

1313
type Config struct {
14-
log_level string
15-
own_registry bool
16-
own_registry_adr string
17-
own_registry_port string
18-
zot_config_path string
19-
input string
20-
zot_url string
21-
registry string
22-
repository string
23-
user_input string
24-
scheme string
25-
api_version string
26-
image string
27-
harbor_password string
28-
harbor_username string
29-
env string
30-
use_unsecure bool
14+
log_level string
15+
own_registry bool
16+
own_registry_adr string
17+
own_registry_port string
18+
zot_config_path string
19+
input string
20+
zot_url string
21+
registry string
22+
repository string
23+
user_input string
24+
scheme string
25+
api_version string
26+
image string
27+
harbor_password string
28+
harbor_username string
29+
env string
30+
use_unsecure bool
31+
remote_registry_url string
32+
group_name string
33+
state_artifact_name string
3134
}
3235

3336
func GetLogLevel() string {
@@ -122,6 +125,22 @@ func GetHarborUsername() string {
122125
return AppConfig.harbor_username
123126
}
124127

128+
func SetRemoteRegistryURL(url string) {
129+
AppConfig.remote_registry_url = url
130+
}
131+
132+
func GetRemoteRegistryURL() string {
133+
return AppConfig.remote_registry_url
134+
}
135+
136+
func GetGroupName() string {
137+
return AppConfig.group_name
138+
}
139+
140+
func GetStateArtifactName() string {
141+
return AppConfig.state_artifact_name
142+
}
143+
125144
func LoadConfig() (*Config, error) {
126145
viper.SetConfigName("config")
127146
viper.SetConfigType("toml")
@@ -142,17 +161,19 @@ func LoadConfig() (*Config, error) {
142161
}
143162

144163
return &Config{
145-
log_level: viper.GetString("log_level"),
146-
own_registry: viper.GetBool("bring_own_registry"),
147-
own_registry_adr: viper.GetString("own_registry_adr"),
148-
own_registry_port: viper.GetString("own_registry_port"),
149-
zot_config_path: viper.GetString("zotConfigPath"),
150-
input: viper.GetString("url_or_file"),
151-
harbor_password: os.Getenv("HARBOR_PASSWORD"),
152-
harbor_username: os.Getenv("HARBOR_USERNAME"),
153-
env: os.Getenv("ENV"),
154-
zot_url: os.Getenv("ZOT_URL"),
155-
use_unsecure: use_unsecure,
164+
log_level: viper.GetString("log_level"),
165+
own_registry: viper.GetBool("bring_own_registry"),
166+
own_registry_adr: viper.GetString("own_registry_adr"),
167+
own_registry_port: viper.GetString("own_registry_port"),
168+
zot_config_path: viper.GetString("zotConfigPath"),
169+
input: viper.GetString("url_or_file"),
170+
harbor_password: os.Getenv("HARBOR_PASSWORD"),
171+
harbor_username: os.Getenv("HARBOR_USERNAME"),
172+
env: os.Getenv("ENV"),
173+
zot_url: os.Getenv("ZOT_URL"),
174+
use_unsecure: use_unsecure,
175+
group_name: os.Getenv("GROUP_NAME"),
176+
state_artifact_name: os.Getenv("STATE_ARTIFACT_NAME"),
156177
}, nil
157178
}
158179

internal/config/state_aritfact.go

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package config
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
10+
"oras.land/oras-go/v2"
11+
"oras.land/oras-go/v2/content/file"
12+
"oras.land/oras-go/v2/registry/remote"
13+
"oras.land/oras-go/v2/registry/remote/auth"
14+
"oras.land/oras-go/v2/registry/remote/retry"
15+
)
16+
17+
// Registry defines an interface for registry operations
18+
type StateReader interface {
19+
// GetRegistryURL returns the URL of the registry
20+
GetRegistryURL() string
21+
// GetRegistryType returns the list of artifacts that needs to be pulled
22+
GetArtifacts() []ArtifactReader
23+
// GetArtifactByRepository takes in the repository name and returns the artifact associated with it
24+
GetArtifactByRepository(repo string) (ArtifactReader, error)
25+
}
26+
27+
type State struct {
28+
Registry string `json:"registry"`
29+
Artifacts []Artifact `json:"artifacts"`
30+
}
31+
32+
func NewState(artifact *Artifact) StateReader {
33+
state := &State{
34+
Registry: "",
35+
Artifacts: []Artifact{*artifact},
36+
}
37+
return state
38+
}
39+
40+
func (a *State) GetRegistryURL() string {
41+
return a.Registry
42+
}
43+
44+
func (a *State) GetArtifacts() []ArtifactReader {
45+
var artifact_readers []ArtifactReader
46+
for _, artifact := range a.Artifacts {
47+
artifact_readers = append(artifact_readers, &artifact)
48+
}
49+
return artifact_readers
50+
}
51+
52+
func (a *State) GetArtifactByRepository(repo string) (ArtifactReader, error) {
53+
for _, artifact := range a.Artifacts {
54+
if artifact.GetRepository() == repo {
55+
return &artifact, nil
56+
}
57+
}
58+
return &Artifact{}, fmt.Errorf("artifact not found in the list")
59+
}
60+
61+
type StateArtifactFetcher interface {
62+
// Fetches the state artifact from the registry
63+
FetchStateArtifact() error
64+
}
65+
66+
type URLStateArtifactFetcher struct {
67+
url string
68+
group_name string
69+
state_artifact_name string
70+
state_artifact_reader StateReader
71+
}
72+
73+
func NewURLStateArtifactFetcher() StateArtifactFetcher {
74+
url := GetRemoteRegistryURL()
75+
// Trim the "https://" or "http://" prefix if present
76+
if len(url) >= 8 && url[:8] == "https://" {
77+
url = url[8:]
78+
} else if len(url) >= 7 && url[:7] == "http://" {
79+
url = url[7:]
80+
}
81+
artifact := NewArtifact()
82+
state_artifact_reader := NewState(artifact.(*Artifact))
83+
return &URLStateArtifactFetcher{
84+
url: url,
85+
group_name: GetGroupName(),
86+
state_artifact_name: GetStateArtifactName(),
87+
state_artifact_reader: state_artifact_reader,
88+
}
89+
}
90+
91+
type FileStateArtifactFetcher struct {
92+
filePath string
93+
}
94+
95+
func (f *URLStateArtifactFetcher) FetchStateArtifact() error {
96+
cwd, err := os.Getwd()
97+
if err != nil {
98+
return fmt.Errorf("failed to get current working directory: %v", err)
99+
}
100+
// Creating a file store in the current working directory
101+
fs, err := file.New(fmt.Sprintf("%s/state-artifact", cwd))
102+
if err != nil {
103+
return fmt.Errorf("failed to create file store: %v", err)
104+
}
105+
defer fs.Close()
106+
107+
ctx := context.Background()
108+
109+
repo, err := remote.NewRepository(fmt.Sprintf("%s/%s/%s", f.url, f.group_name, f.state_artifact_name))
110+
if err != nil {
111+
return fmt.Errorf("failed to create remote repository: %v", err)
112+
}
113+
114+
// Setting up the authentication for the remote registry
115+
repo.Client = &auth.Client{
116+
Client: retry.DefaultClient,
117+
Cache: auth.NewCache(),
118+
Credential: auth.StaticCredential(
119+
f.url,
120+
auth.Credential{
121+
Username: GetHarborUsername(),
122+
Password: GetHarborPassword(),
123+
},
124+
),
125+
}
126+
// Copy from the remote repository to the file store
127+
tag := "latest"
128+
_, err = oras.Copy(ctx, repo, tag, fs, tag, oras.DefaultCopyOptions)
129+
if err != nil {
130+
return fmt.Errorf("failed to copy from remote repository to file store: %v", err)
131+
}
132+
stateArtifactDir := filepath.Join(cwd, "state-artifact")
133+
// Find the state artifact file in the state-artifact directory that is created temporarily
134+
err = filepath.Walk(stateArtifactDir, func(path string, info os.FileInfo, err error) error {
135+
if err != nil {
136+
return err
137+
}
138+
if filepath.Ext(info.Name()) == ".json" {
139+
content, err := os.ReadFile(path)
140+
if err != nil {
141+
return err
142+
}
143+
fmt.Printf("Contents of %s:\n", info.Name())
144+
fmt.Println(string(content))
145+
146+
state_artifact_reader, err := FromJSON(content, f.state_artifact_reader.(*State))
147+
if err != nil {
148+
return fmt.Errorf("failed to parse the state artifact file: %v", err)
149+
}
150+
fmt.Println(state_artifact_reader)
151+
152+
}
153+
return nil
154+
})
155+
156+
if err != nil {
157+
return fmt.Errorf("failed to read the state artifact file: %v", err)
158+
}
159+
// Clean up everything inside the state-artifact folder
160+
err = os.RemoveAll(stateArtifactDir)
161+
if err != nil {
162+
return fmt.Errorf("failed to remove state-artifact directory: %v", err)
163+
}
164+
return nil
165+
}
166+
167+
// FromJSON parses the input JSON data into a StateArtifactReader
168+
func FromJSON(data []byte, reg *State) (StateReader, error) {
169+
170+
if err := json.Unmarshal(data, &reg); err != nil {
171+
fmt.Print("Error in unmarshalling")
172+
return nil, err
173+
}
174+
fmt.Print(reg)
175+
// Validation
176+
if reg.Registry == "" {
177+
return nil, fmt.Errorf("registry URL is required")
178+
}
179+
return reg, nil
180+
}

main.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,14 @@ func processInput(ctx context.Context, log *zerolog.Logger) (store.ImageFetcher,
128128
}
129129

130130
log.Info().Msg("Input is a valid URL")
131+
config.SetRemoteRegistryURL(input)
132+
state_arifact_fetcher := config.NewURLStateArtifactFetcher()
133+
if err := state_arifact_fetcher.FetchStateArtifact(); err != nil {
134+
log.Error().Err(err).Msg("Error fetching state artifact")
135+
return nil, err
136+
}
131137
fetcher := store.RemoteImageListFetcher(ctx, input)
132-
utils.SetUrlConfig(input)
138+
// utils.SetUrlConfig(input)
133139
return fetcher, nil
134140
}
135141

0 commit comments

Comments
 (0)