diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..31978d7 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,42 @@ +{ + "name": "Registrywatcher Dev Container - Go", + "dockerComposeFile": "docker-compose.yml", + "service": "devcontainer", + "workspaceFolder": "/workspaces/registrywatcher", + "forwardPorts": [5432], + "portsAttributes": { + "5432": {"label": "PostgreSQL port", "onAutoForward": "silent"} + }, + "customizations": { + "vscode": { + "extensions": [ + "golang.go", + "ms-azuretools.vscode-docker", + "GitHub.copilot", + "waderyan.gitblame", + "DavidAnson.vscode-markdownlint", + "mtxr.sqltools", + "mtxr.sqltools-driver-pg" + ], + "settings": { + "[go]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": true + } + }, + "sqltools.connections": [ + { + "name": "Local database", + "driver": "PostgreSQL", + "server": "localhost", + "port": 5432, + "database": "lauth", + "username": "postgres", + "password": "Password123" + } + ] + } + } + } +} \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..f0e637f --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.8' +services: + backend: + image: mcr.microsoft.com/devcontainers/go:0-1.17-bullseye + volumes: + - ../..:/workspaces:cached + network_mode: service:db + command: sleep infinity + environment: + DATABASE_URL: postgresql://registry-watcher:registry-watcher@db/registry-watcher?sslmode=disable + VAULT_TOKEN: ${VAULT_TOKEN} + NOMAD_TOKEN: ${NOMAD_TOKEN} + + db: + image: postgres:9.6-alpine + restart: unless-stopped + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_USER: registry-watcher + POSTGRES_DB: registry-watcher + POSTGRES_PASSWORD: registry-watcher + +volumes: + postgres-data: \ No newline at end of file diff --git a/client/client.go b/client/client.go index f393130..1dc375f 100644 --- a/client/client.go +++ b/client/client.go @@ -9,12 +9,13 @@ import ( "github.com/dsaidgovsg/registrywatcher/log" "github.com/dsaidgovsg/registrywatcher/utils" "github.com/spf13/viper" + "gorm.io/gorm" ) type Clients struct { NomadClient *NomadClient DockerRegistryClient *DockerRegistryClient - PostgresClient *PostgresClient + PostgresClient *gorm.DB DockerhubApi *DockerhubApi DockerTags sync.Map DigestMap sync.Map @@ -81,10 +82,11 @@ func (client *Clients) GetCachedTagDigest(repoName string) (string, error) { // fetches the CACHED pinned tag func (client *Clients) GetFormattedPinnedTag(repoName string) (string, error) { - pinnedTag, err := client.PostgresClient.GetPinnedTag(repoName) - if err != nil { - return "", err - } + // pinnedTag, err := client.PostgresClient.GetPinnedTag(repoName) + // if err != nil { + // return "", err + // } + pinnedTag := "" if pinnedTag == "" { tags, err := client.GetCachedTags(repoName) if err != nil { @@ -92,7 +94,7 @@ func (client *Clients) GetFormattedPinnedTag(repoName string) (string, error) { } pinnedTag, err = utils.GetLatestReleaseTag(tags) } - return pinnedTag, err + return pinnedTag, nil } func (client *Clients) DeployPinnedTag(conf *viper.Viper, repoName string) { @@ -265,21 +267,23 @@ func (client *Clients) updateCaches(repoName string) { // this function compares cached values with the actual values, // so only update the cache before returning non-error cases func (client *Clients) ShouldDeploy(repoName string) (bool, error) { - autoDeploy, err := client.PostgresClient.GetAutoDeployFlag(repoName) - if err != nil { - log.LogAppErr(fmt.Sprintf("Couldn't fetch whether to deploy flag while checking whether to deploy for %s", repoName), err) - return false, err - } + // autoDeploy, err := client.PostgresClient.GetAutoDeployFlag(repoName) + // if err != nil { + // log.LogAppErr(fmt.Sprintf("Couldn't fetch whether to deploy flag while checking whether to deploy for %s", repoName), err) + // return false, err + // } + autoDeploy := false if !autoDeploy { client.updateCaches(repoName) return false, nil } - pinnedTag, err := client.PostgresClient.GetPinnedTag(repoName) - if err != nil { - log.LogAppErr(fmt.Sprintf("Couldn't fetch pinned tag while checking whether to deploy for %s", repoName), err) - return false, err - } + // pinnedTag, err := client.PostgresClient.GetPinnedTag(repoName) + // if err != nil { + // log.LogAppErr(fmt.Sprintf("Couldn't fetch pinned tag while checking whether to deploy for %s", repoName), err) + // return false, err + // } + pinnedTag := "" isDigestChanged, err := client.isTagDigestChanged(repoName) if err != nil { log.LogAppErr(fmt.Sprintf("Couldn't check tag digest changed while checking whether to deploy for %s", repoName), err) diff --git a/client/postgres_client.go b/client/postgres_client.go index be340fa..7ff60d2 100644 --- a/client/postgres_client.go +++ b/client/postgres_client.go @@ -2,14 +2,13 @@ package client import ( "database/sql" - "math" - "os" - "time" "github.com/jmoiron/sqlx" _ "github.com/lib/pq" "github.com/pkg/errors" "github.com/spf13/viper" + "gorm.io/driver/postgres" + "gorm.io/gorm" ) type PostgresClient struct { @@ -19,47 +18,52 @@ type PostgresClient struct { // Initialize creates tables if they do not exist // cloud agnostic function -func InitializePostgresClient(conf *viper.Viper) (*PostgresClient, error) { - client := PostgresClient{ - conf: conf, - } - var dburl string - if len(os.Getenv("DATABASE_URL")) > 0 { - dburl = os.Getenv("DATABASE_URL") - } else { - dburl = conf.GetString("database_url") - } - createSchema := conf.GetBool("create_database_schema") - - var err error - if client.db, err = sqlx.Open("postgres", dburl); err != nil { - return &client, errors.Wrap(err, "unable to open postgres db") - } - - if createSchema { - // Since this happens at initialization we - // could encounter racy conditions waiting for pg - // to become available. Wait for it a bit - if err = client.db.Ping(); err != nil { - // Try 3 more times - // 5, 10, 20 - for i := 0; i < 3 && err != nil; i++ { - time.Sleep(time.Duration(5*math.Pow(2, float64(i))) * time.Second) - err = client.db.Ping() - } - if err != nil { - return &client, errors.Wrap(err, "error trying to connect to postgres db, retries exhausted") - } - } - - if err = client.createTables(); err != nil { - return &client, errors.Wrap(err, "problem executing create tables sql") - } - if err = client.initRows(); err != nil { - return &client, errors.Wrap(err, "problem executing init row sql") - } +func InitializePostgresClient(conf *viper.Viper) (*gorm.DB, error) { + // client := PostgresClient{ + // conf: conf, + // } + // var dburl string + // if len(os.Getenv("DATABASE_URL")) > 0 { + // dburl = os.Getenv("DATABASE_URL") + // } else { + // dburl = conf.GetString("database_url") + // } + // createSchema := conf.GetBool("create_database_schema") + + // var err error + // if client.db, err = sqlx.Open("postgres", dburl); err != nil { + // return &client, errors.Wrap(err, "unable to open postgres db") + // } + + // if createSchema { + // // Since this happens at initialization we + // // could encounter racy conditions waiting for pg + // // to become available. Wait for it a bit + // if err = client.db.Ping(); err != nil { + // // Try 3 more times + // // 5, 10, 20 + // for i := 0; i < 3 && err != nil; i++ { + // time.Sleep(time.Duration(5*math.Pow(2, float64(i))) * time.Second) + // err = client.db.Ping() + // } + // if err != nil { + // return &client, errors.Wrap(err, "error trying to connect to postgres db, retries exhausted") + // } + // } + + // if err = client.createTables(); err != nil { + // return &client, errors.Wrap(err, "problem executing create tables sql") + // } + // if err = client.initRows(); err != nil { + // return &client, errors.Wrap(err, "problem executing init row sql") + // } + // } + dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai" + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + return nil, err } - return &client, nil + return db, nil } func (client *PostgresClient) createTables() error { diff --git a/go.mod b/go.mod index 2d6cfcb..15bbe4e 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,10 @@ require ( github.com/nlopes/slack v0.6.0 github.com/pkg/errors v0.9.1 github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 go.uber.org/zap v1.21.0 + gorm.io/driver/postgres v1.5.6 + gorm.io/gorm v1.25.7 ) require ( @@ -27,6 +29,12 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/hcl v1.0.1-0.20201016140508-a07e7d50bbee // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect + github.com/jackc/pgx/v5 v5.5.3 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/magiconair/properties v1.8.6 // indirect @@ -48,10 +56,11 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/goleak v1.1.12 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect - golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/crypto v0.20.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 56bbffa..1913e5d 100644 --- a/go.sum +++ b/go.sum @@ -276,6 +276,20 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/pgx/v5 v5.5.3 h1:Ces6/M3wbDXYpM8JyyPD57ivTtJACFZJd885pdIaV2s= +github.com/jackc/pgx/v5 v5.5.3/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -409,6 +423,7 @@ github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiu github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -416,8 +431,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -430,6 +446,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= @@ -461,9 +478,15 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -499,6 +522,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -545,8 +570,12 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -579,6 +608,10 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -656,10 +689,21 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -668,8 +712,12 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -728,6 +776,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -927,6 +977,11 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.5.6 h1:ydr9xEd5YAM0vxVDY0X139dyzNz10spDiDlC7+ibLeU= +gorm.io/driver/postgres v1.5.6/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/main.go b/main.go index fe0d71e..ae5b434 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,6 @@ import ( "github.com/dsaidgovsg/registrywatcher/client" "github.com/dsaidgovsg/registrywatcher/config" "github.com/dsaidgovsg/registrywatcher/log" - "github.com/dsaidgovsg/registrywatcher/utils" "github.com/dsaidgovsg/registrywatcher/worker" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" @@ -21,7 +20,7 @@ func main() { clients := client.SetUpClients(conf) - SetUpWorkers(conf, clients) + // SetUpWorkers(conf, clients) log.SetUpLogger() @@ -50,10 +49,10 @@ type Config struct { func SetUpRouter(conf *viper.Viper, clients *client.Clients) *gin.Engine { r := gin.Default() - handler := Handler{ - clients: clients, - conf: conf, - } + // handler := Handler{ + // clients: clients, + // conf: conf, + // } routerConf := Config{ CORSAllowOrigin: "*", @@ -65,11 +64,11 @@ func SetUpRouter(conf *viper.Viper, clients *client.Clients) *gin.Engine { r.Use(corsMiddleware(&routerConf)) r.GET("/ping", HealthCheckHandler) - r.POST("/tags/:repo_name/reset", handler.ResetTagHandler) - r.POST("/tags/:repo_name", handler.DeployTagHandler) - r.GET("/tags/:repo_name", handler.GetTagHandler) - r.GET("/repos", handler.RepoSummaryHandler) - r.GET("/debug/caches", handler.CacheSummaryHandler) + // r.POST("/tags/:repo_name/reset", handler.ResetTagHandler) + // r.POST("/tags/:repo_name", handler.DeployTagHandler) + // r.GET("/tags/:repo_name", handler.GetTagHandler) + // r.GET("/repos", handler.RepoSummaryHandler) + // r.GET("/debug/caches", handler.CacheSummaryHandler) return r } @@ -108,249 +107,249 @@ type deployBody struct { AutoDeploy *bool `json:"auto_deploy",omitempty` } -func (h *Handler) ResetTagHandler(c *gin.Context) { - - pinnedTag := "" - - // check if repoName is valid - repoName := c.Param("repo_name") - validName := false - for _, repo := range h.conf.GetStringSlice("watched_repositories") { - if repoName == repo { - validName = true - break - } - } - if !validName { - _, registryDomain, _, _ := utils.ExtractRegistryInfo(h.conf, repoName) - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Error: The specified repo name %s is not inside the docker repository registry %s", repoName, registryDomain), - }) - return - } - - // if originalTag == pinnedTag, just terminate early - originalTag, err := h.clients.PostgresClient.GetPinnedTag(repoName) - if originalTag == pinnedTag { - c.JSON(200, gin.H{ - "message": fmt.Sprintf("pinned_tag is already %s", pinnedTag), - }) - return - } - - // update auto deployment - _ = h.clients.PostgresClient.UpdateAutoDeployFlag(repoName, true) - - // update tag - err = h.clients.PostgresClient.UpdatePinnedTag(repoName, pinnedTag) - - if err != nil { - _ = h.clients.PostgresClient.UpdatePinnedTag(repoName, originalTag) - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Error: Failed to update pinned tag, %s", err), - }) - } else { - log.LogAppInfo(fmt.Sprintf("Updated pinned_tag for repo %s from %s to %s succesfully, deployment of pinned_tag will happen shortly", repoName, originalTag, pinnedTag)) - h.clients.DeployPinnedTag(h.conf, repoName) - c.JSON(200, gin.H{ - "message": fmt.Sprintf("Deploying to %s", pinnedTag), - }) - } -} - -func (h *Handler) DeployTagHandler(c *gin.Context) { - - // check if repoName is valid - repoName := c.Param("repo_name") - validName := false - for _, repo := range h.conf.GetStringSlice("watched_repositories") { - if repoName == repo { - validName = true - break - } - } - if !validName { - _, registryDomain, _, _ := utils.ExtractRegistryInfo(h.conf, repoName) - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Error: The specified repo name %s is not inside the docker repository registry %s", repoName, registryDomain), - }) - return - } - - // check that either pinnedTag or autoDeploy is given - var deployBody deployBody - err := c.BindJSON(&deployBody) - if err != nil { - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Error: %s", err), - }) - return - } else if deployBody.PinnedTag == nil && deployBody.AutoDeploy == nil { - c.JSON(400, gin.H{ - "message": "Either pinned_tag or auto_deploy must be specified.", - }) - return - } - - var newAutoDeployFlag bool - // set autoDeploy if its present - if deployBody.AutoDeploy != nil { - newAutoDeployFlag = *deployBody.AutoDeploy - currentAutoDeployFlag, _ := h.clients.PostgresClient.GetAutoDeployFlag(repoName) - if newAutoDeployFlag != currentAutoDeployFlag { - _ = h.clients.PostgresClient.UpdateAutoDeployFlag(repoName, newAutoDeployFlag) - var msg string - if newAutoDeployFlag { - msg = fmt.Sprintf("Turned on auto deployment for repo `%s`", repoName) - } else { - msg = fmt.Sprintf("Turned off auto deployment for repo `%s`", repoName) - } - utils.PostSlackUpdate(h.conf, msg) - log.LogAppInfo(msg) - } else { - log.LogAppInfo(fmt.Sprintf("Auto deployment is already set to %s", strconv.FormatBool(newAutoDeployFlag))) - } - } - - // exit if only autoDeploy in body - if deployBody.PinnedTag == nil { - c.JSON(200, gin.H{ - "message": fmt.Sprintf("Auto deployment set to %s", strconv.FormatBool(newAutoDeployFlag)), - }) - return - } - - // check if tag is valid - pinnedTag := *deployBody.PinnedTag - tags, err := h.clients.DockerRegistryClient.GetAllTags(repoName) - if err != nil || !utils.IsTagDeployable(pinnedTag, tags) { - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Error: The specified pinned_tag %s is not inside the docker repository registry %s", pinnedTag, repoName), - }) - return - } - - // can terminate early if originalTag == pinnedTag - originalTag, err := h.clients.PostgresClient.GetPinnedTag(repoName) - if originalTag == pinnedTag { - h.clients.DeployPinnedTag(h.conf, repoName) - c.JSON(200, gin.H{ - "message": fmt.Sprintf("Deploying to %s", pinnedTag), - }) - return - } - - // update tag - err = h.clients.PostgresClient.UpdatePinnedTag(repoName, pinnedTag) - - if err != nil { - _ = h.clients.PostgresClient.UpdatePinnedTag(repoName, originalTag) - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Error: Failed to update pinned tag, %s", err), - }) - } else { - log.LogAppInfo(fmt.Sprintf("Updated pinned_tag for repo %s from %s to %s succesfully, deployment of pinned_tag will happen shortly", repoName, originalTag, pinnedTag)) - h.clients.DeployPinnedTag(h.conf, repoName) - c.JSON(200, gin.H{ - "message": fmt.Sprintf("Deploying to %s", pinnedTag), - }) - } -} - -func (h *Handler) GetTagHandler(c *gin.Context) { - - repoName := c.Param("repo_name") - - invalidRepoName := true - for _, repo := range h.conf.GetStringSlice("watched_repositories") { - if repo == repoName { - invalidRepoName = false - break - } - } - if invalidRepoName { - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Error: Repo %s is not being watched", repoName), - }) - return - } - - tag, err := h.clients.PostgresClient.GetPinnedTag(repoName) - var rtn string - if tag == "" { - tags, err := h.clients.DockerRegistryClient.GetAllTags(repoName) - rtn, err = utils.GetLatestReleaseTag(tags) - if err != nil { - c.JSON(400, gin.H{ - "message": fmt.Sprintf("No valid tags %s for repo %s, err: %s", tags, repoName, err), - }) - } - } else { - rtn = tag - } - - if err != nil { - c.JSON(400, gin.H{ - "message": fmt.Sprintf("Unable to fetch repo %s tag, err: %s", repoName, err), - }) - } else { - c.JSON(200, gin.H{ - "repo_tag": rtn, - }) - } -} - -func (h *Handler) RepoSummaryHandler(c *gin.Context) { - - rtn := map[string]map[string]interface{}{} - - tagMap, err := h.clients.PostgresClient.GetAllTags() - for _, repoName := range h.conf.GetStringSlice("watched_repositories") { - var tag string - if _, ok := tagMap[repoName]; ok { - tag = tagMap[repoName] - } else { - log.LogAppErr(fmt.Sprintf("Couldn't fetch tag from database for endpoint summary handler for repo %s", repoName), err) - continue - } - tags, err := h.clients.GetCachedTags(repoName) - if err != nil { - log.LogAppErr(fmt.Sprintf("Couldn't fetch tags from cache for endpoint summary handler for repo %s", repoName), err) - continue - } - tagValue, err := h.clients.GetFormattedPinnedTag(repoName) - if err != nil { - log.LogAppErr(fmt.Sprintf("Couldn't fetch pinned tag for endpoint summary handler for repo %s", repoName), err) - continue - } - autoDeployFlag, err := h.clients.PostgresClient.GetAutoDeployFlag(repoName) - if err != nil { - log.LogAppErr(fmt.Sprintf("Couldn't fetch auto deploy flag for endpoint summary handler for repo %s", repoName), err) - continue - } - rtn[repoName] = map[string]interface{}{ - "pinned_tag": tag, - "pinned_tag_value": tagValue, - "tags": tags, - "auto_deploy": autoDeployFlag, - } - } - - c.JSON(200, rtn) -} - -func (h *Handler) CacheSummaryHandler(c *gin.Context) { - - rtn := map[string]map[string]interface{}{} - - for _, repoName := range h.conf.GetStringSlice("watched_repositories") { - cachedTagDigest, _ := h.clients.GetCachedTagDigest(repoName) - tags, _ := h.clients.GetCachedTags(repoName) - rtn[repoName] = map[string]interface{}{ - "cached_tags": tags, - "cached_digest": cachedTagDigest, - } - } - - c.JSON(200, rtn) -} +// func (h *Handler) ResetTagHandler(c *gin.Context) { + +// pinnedTag := "" + +// // check if repoName is valid +// repoName := c.Param("repo_name") +// validName := false +// for _, repo := range h.conf.GetStringSlice("watched_repositories") { +// if repoName == repo { +// validName = true +// break +// } +// } +// if !validName { +// _, registryDomain, _, _ := utils.ExtractRegistryInfo(h.conf, repoName) +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Error: The specified repo name %s is not inside the docker repository registry %s", repoName, registryDomain), +// }) +// return +// } + +// // if originalTag == pinnedTag, just terminate early +// originalTag, err := h.clients.PostgresClient.GetPinnedTag(repoName) +// if originalTag == pinnedTag { +// c.JSON(200, gin.H{ +// "message": fmt.Sprintf("pinned_tag is already %s", pinnedTag), +// }) +// return +// } + +// // update auto deployment +// _ = h.clients.PostgresClient.UpdateAutoDeployFlag(repoName, true) + +// // update tag +// err = h.clients.PostgresClient.UpdatePinnedTag(repoName, pinnedTag) + +// if err != nil { +// _ = h.clients.PostgresClient.UpdatePinnedTag(repoName, originalTag) +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Error: Failed to update pinned tag, %s", err), +// }) +// } else { +// log.LogAppInfo(fmt.Sprintf("Updated pinned_tag for repo %s from %s to %s succesfully, deployment of pinned_tag will happen shortly", repoName, originalTag, pinnedTag)) +// h.clients.DeployPinnedTag(h.conf, repoName) +// c.JSON(200, gin.H{ +// "message": fmt.Sprintf("Deploying to %s", pinnedTag), +// }) +// } +// } + +// func (h *Handler) DeployTagHandler(c *gin.Context) { + +// // check if repoName is valid +// repoName := c.Param("repo_name") +// validName := false +// for _, repo := range h.conf.GetStringSlice("watched_repositories") { +// if repoName == repo { +// validName = true +// break +// } +// } +// if !validName { +// _, registryDomain, _, _ := utils.ExtractRegistryInfo(h.conf, repoName) +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Error: The specified repo name %s is not inside the docker repository registry %s", repoName, registryDomain), +// }) +// return +// } + +// // check that either pinnedTag or autoDeploy is given +// var deployBody deployBody +// err := c.BindJSON(&deployBody) +// if err != nil { +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Error: %s", err), +// }) +// return +// } else if deployBody.PinnedTag == nil && deployBody.AutoDeploy == nil { +// c.JSON(400, gin.H{ +// "message": "Either pinned_tag or auto_deploy must be specified.", +// }) +// return +// } + +// var newAutoDeployFlag bool +// // set autoDeploy if its present +// if deployBody.AutoDeploy != nil { +// newAutoDeployFlag = *deployBody.AutoDeploy +// currentAutoDeployFlag, _ := h.clients.PostgresClient.GetAutoDeployFlag(repoName) +// if newAutoDeployFlag != currentAutoDeployFlag { +// _ = h.clients.PostgresClient.UpdateAutoDeployFlag(repoName, newAutoDeployFlag) +// var msg string +// if newAutoDeployFlag { +// msg = fmt.Sprintf("Turned on auto deployment for repo `%s`", repoName) +// } else { +// msg = fmt.Sprintf("Turned off auto deployment for repo `%s`", repoName) +// } +// utils.PostSlackUpdate(h.conf, msg) +// log.LogAppInfo(msg) +// } else { +// log.LogAppInfo(fmt.Sprintf("Auto deployment is already set to %s", strconv.FormatBool(newAutoDeployFlag))) +// } +// } + +// // exit if only autoDeploy in body +// if deployBody.PinnedTag == nil { +// c.JSON(200, gin.H{ +// "message": fmt.Sprintf("Auto deployment set to %s", strconv.FormatBool(newAutoDeployFlag)), +// }) +// return +// } + +// // check if tag is valid +// pinnedTag := *deployBody.PinnedTag +// tags, err := h.clients.DockerRegistryClient.GetAllTags(repoName) +// if err != nil || !utils.IsTagDeployable(pinnedTag, tags) { +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Error: The specified pinned_tag %s is not inside the docker repository registry %s", pinnedTag, repoName), +// }) +// return +// } + +// // can terminate early if originalTag == pinnedTag +// originalTag, err := h.clients.PostgresClient.GetPinnedTag(repoName) +// if originalTag == pinnedTag { +// h.clients.DeployPinnedTag(h.conf, repoName) +// c.JSON(200, gin.H{ +// "message": fmt.Sprintf("Deploying to %s", pinnedTag), +// }) +// return +// } + +// // update tag +// err = h.clients.PostgresClient.UpdatePinnedTag(repoName, pinnedTag) + +// if err != nil { +// _ = h.clients.PostgresClient.UpdatePinnedTag(repoName, originalTag) +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Error: Failed to update pinned tag, %s", err), +// }) +// } else { +// log.LogAppInfo(fmt.Sprintf("Updated pinned_tag for repo %s from %s to %s succesfully, deployment of pinned_tag will happen shortly", repoName, originalTag, pinnedTag)) +// h.clients.DeployPinnedTag(h.conf, repoName) +// c.JSON(200, gin.H{ +// "message": fmt.Sprintf("Deploying to %s", pinnedTag), +// }) +// } +// } + +// func (h *Handler) GetTagHandler(c *gin.Context) { + +// repoName := c.Param("repo_name") + +// invalidRepoName := true +// for _, repo := range h.conf.GetStringSlice("watched_repositories") { +// if repo == repoName { +// invalidRepoName = false +// break +// } +// } +// if invalidRepoName { +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Error: Repo %s is not being watched", repoName), +// }) +// return +// } + +// tag, err := h.clients.PostgresClient.GetPinnedTag(repoName) +// var rtn string +// if tag == "" { +// tags, err := h.clients.DockerRegistryClient.GetAllTags(repoName) +// rtn, err = utils.GetLatestReleaseTag(tags) +// if err != nil { +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("No valid tags %s for repo %s, err: %s", tags, repoName, err), +// }) +// } +// } else { +// rtn = tag +// } + +// if err != nil { +// c.JSON(400, gin.H{ +// "message": fmt.Sprintf("Unable to fetch repo %s tag, err: %s", repoName, err), +// }) +// } else { +// c.JSON(200, gin.H{ +// "repo_tag": rtn, +// }) +// } +// } + +// func (h *Handler) RepoSummaryHandler(c *gin.Context) { + +// rtn := map[string]map[string]interface{}{} + +// tagMap, err := h.clients.PostgresClient.GetAllTags() +// for _, repoName := range h.conf.GetStringSlice("watched_repositories") { +// var tag string +// if _, ok := tagMap[repoName]; ok { +// tag = tagMap[repoName] +// } else { +// log.LogAppErr(fmt.Sprintf("Couldn't fetch tag from database for endpoint summary handler for repo %s", repoName), err) +// continue +// } +// tags, err := h.clients.GetCachedTags(repoName) +// if err != nil { +// log.LogAppErr(fmt.Sprintf("Couldn't fetch tags from cache for endpoint summary handler for repo %s", repoName), err) +// continue +// } +// tagValue, err := h.clients.GetFormattedPinnedTag(repoName) +// if err != nil { +// log.LogAppErr(fmt.Sprintf("Couldn't fetch pinned tag for endpoint summary handler for repo %s", repoName), err) +// continue +// } +// autoDeployFlag, err := h.clients.PostgresClient.GetAutoDeployFlag(repoName) +// if err != nil { +// log.LogAppErr(fmt.Sprintf("Couldn't fetch auto deploy flag for endpoint summary handler for repo %s", repoName), err) +// continue +// } +// rtn[repoName] = map[string]interface{}{ +// "pinned_tag": tag, +// "pinned_tag_value": tagValue, +// "tags": tags, +// "auto_deploy": autoDeployFlag, +// } +// } + +// c.JSON(200, rtn) +// } + +// func (h *Handler) CacheSummaryHandler(c *gin.Context) { + +// rtn := map[string]map[string]interface{}{} + +// for _, repoName := range h.conf.GetStringSlice("watched_repositories") { +// cachedTagDigest, _ := h.clients.GetCachedTagDigest(repoName) +// tags, _ := h.clients.GetCachedTags(repoName) +// rtn[repoName] = map[string]interface{}{ +// "cached_tags": tags, +// "cached_digest": cachedTagDigest, +// } +// } + +// c.JSON(200, rtn) +// } diff --git a/models/models.go b/models/models.go new file mode 100644 index 0000000..bdd41a7 --- /dev/null +++ b/models/models.go @@ -0,0 +1,22 @@ +package models + +import ( + "time" + + "gorm.io/gorm" +) + +type Repository struct { + gorm.Model + Name string `gorm:"unique"` + PinnedTag string + AutoDeploy bool +} + +type Tag struct { + gorm.Model + RepositoryID uint + Name string + Digest string + LastPushedAt time.Time +}