blob: 097a6b0975beaf766d2c1988d171354b26a38735 [file] [log] [blame]
Mohammed Naserdabb1dc2022-09-06 14:45:59 -04001package image_repositories
2
3import (
Mohammed Naseraaba50a2022-09-06 16:15:36 -04004 "context"
Mohammed Naserdabb1dc2022-09-06 14:45:59 -04005 _ "embed"
Mohammed Naseraaba50a2022-09-06 16:15:36 -04006 "encoding/json"
7 "fmt"
Mohammed Naserdabb1dc2022-09-06 14:45:59 -04008 "io"
Mohammed Naseraaba50a2022-09-06 16:15:36 -04009 "net/http"
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040010 "text/template"
11
12 "github.com/go-git/go-billy/v5"
Mohammed Naseraaba50a2022-09-06 16:15:36 -040013 "github.com/google/go-github/v47/github"
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040014)
15
16//go:embed template/Dockerfile
17var dockerfileTemplate string
18
19type Dockerfile struct {
Mohammed Naser5a4eb802022-09-14 15:19:29 -040020 Project string
21
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040022 BindepImage string
23 BindepImageTag string
24 BuilderImage string
25 BuilderImageTag string
26 RuntimeImage string
27 RuntimeImageTag string
28
29 template *template.Template
30}
31
Mohammed Naseraaba50a2022-09-06 16:15:36 -040032func NewDockerfile(ctx context.Context, ir *ImageRepository) (*Dockerfile, error) {
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040033 tmpl, err := template.New("Dockerfile").Parse(dockerfileTemplate)
34 if err != nil {
35 return nil, err
36 }
37
Mohammed Naser96c23ef2022-09-08 19:19:23 -040038 builderImageTag, err := getImageTag(ctx, ir.githubClient, "docker-openstack-builder", "openstack-builder-focal")
39 if err != nil {
40 return nil, err
41 }
42
Mohammed Naseraaba50a2022-09-06 16:15:36 -040043 runtimeImageTag, err := getImageTag(ctx, ir.githubClient, "docker-openstack-runtime", "openstack-runtime-focal")
44 if err != nil {
45 return nil, err
46 }
47
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040048 return &Dockerfile{
Mohammed Naser5a4eb802022-09-14 15:19:29 -040049 Project: ir.Project,
50
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040051 BindepImage: "quay.io/vexxhost/bindep-loci",
52 BindepImageTag: "latest",
53 BuilderImage: "quay.io/vexxhost/openstack-builder-focal",
Mohammed Naser96c23ef2022-09-08 19:19:23 -040054 BuilderImageTag: builderImageTag,
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040055 RuntimeImage: "quay.io/vexxhost/openstack-runtime-focal",
Mohammed Naseraaba50a2022-09-06 16:15:36 -040056 RuntimeImageTag: runtimeImageTag,
Mohammed Naserdabb1dc2022-09-06 14:45:59 -040057
58 template: tmpl,
59 }, nil
60}
61
Mohammed Naseraaba50a2022-09-06 16:15:36 -040062type quayTagList struct {
63 Tags []quayTag `json:"tags"`
64 Page int `json:"page"`
65 HasAdditional bool `json:"has_additional"`
66}
67
68type quayTag struct {
69 Name string `json:"name"`
70 Reversion bool `json:"reversion"`
71 StartTimestamp int32 `json:"start_ts"`
72 ManifestDigest string `json:"manifest_digest"`
73 IsManifestList bool `json:"is_manifest_list"`
74 Size int `json:"size"`
75 LastModified string `json:"last_modified"`
76}
77
78func getImageTag(ctx context.Context, client *github.Client, repository string, image string) (string, error) {
79 // Grab the latest SHA from the main branch
80 commit, _, err := client.Repositories.GetCommitSHA1(ctx, "vexxhost", repository, "main", "")
81 if err != nil {
82 return "", err
83 }
84
85 // Check if the image exists in Quay.io
86 url := fmt.Sprintf("https://quay.io/api/v1/repository/vexxhost/%s/tag/?specificTag=%s", image, commit)
87 resp, err := http.Get(url)
88 if err != nil {
89 return "", err
90 }
91
92 // Decode the response
93 var quayResponse quayTagList
94 decoder := json.NewDecoder(resp.Body)
95 decoder.DisallowUnknownFields()
96 err = decoder.Decode(&quayResponse)
97 if err != nil {
98 return "", err
99 }
100
101 // Check if the tag exists
102 if len(quayResponse.Tags) == 0 {
103 return "", fmt.Errorf("tag %s does not exist in quay.io/vexxhost/%s", commit, image)
104 }
105
106 return commit, nil
107}
108
Mohammed Naserdabb1dc2022-09-06 14:45:59 -0400109func (d *Dockerfile) Write(wr io.Writer) error {
110 return d.template.Execute(wr, d)
111}
112
113func (d *Dockerfile) WriteFile(fs billy.Filesystem) error {
114 f, err := fs.Create("Dockerfile")
115 if err != nil {
116 return err
117 }
118 defer f.Close()
119
120 return d.Write(f)
121}