diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 63b33a4..d4964af 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,4 +1,4 @@ -name: Publish Release +name: docker on: workflow_dispatch: @@ -16,7 +16,7 @@ on: branches: ["main"] jobs: - build_docker_release: + build_and_push: runs-on: ubuntu-latest steps: - name: Checkout @@ -33,7 +33,6 @@ jobs: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }} tags: | type=raw,value=latest,enable=${{ github.event_name == 'release' }} - type=sha type=ref,event=branch type=ref,event=pr type=raw,value=${{ inputs.tags }},enable=${{ github.event_name == 'workflow_dispatch' }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c5b55e..a778c71 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,14 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + - name: Run unit tests run: go test -v ./src/tests + - name: Run formatter - run: test -z $(gofmt -l ./src) \ No newline at end of file + run: test -z $(gofmt -l ./src) + + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: v1.55.2 diff --git a/Dockerfile b/Dockerfile index d76989f..098ba2a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,6 @@ RUN go build -o /go/bin/immich-exporter ./src FROM alpine:3.18 COPY --from=builder /go/bin/immich-exporter /go/bin/immich-exporter -COPY package.json /go/bin/ WORKDIR /go/bin diff --git a/go.mod b/go.mod index 77f3dc6..8d1135d 100644 --- a/go.mod +++ b/go.mod @@ -16,5 +16,5 @@ require ( github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect golang.org/x/sys v0.15.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect ) diff --git a/go.sum b/go.sum index 7f85153..a1671f3 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -31,10 +29,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/makefile b/makefile new file mode 100644 index 0000000..9109588 --- /dev/null +++ b/makefile @@ -0,0 +1,14 @@ +build: + go build -o ./qbittorrent-exporter.out ./src +dev : + go run ./src +dev-env : + go run ./src -e +format : + go fmt ./src +lint: + docker run --rm -v ./:/app -w /app golangci/golangci-lint:latest golangci-lint run -v +test: + go test -v ./src/tests +update: + go get -u ./src && go mod tidy \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index 2cb6898..0000000 --- a/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "immich-exporter", - "version": "1.2.0", - "description": "exporter for immich", - "main": "src/main.go", - "scripts": { - "build" : "go build -o ./immich-exporter.out ./src && ./immich-exporter.out", - "build:env" : "go build -o ./immich-exporter.out ./src && ./immich-exporter.out -e", - "dev" : "go run ./src", - "dev:env" : "go run ./src -e", - "test": "go test -v ./src/tests", - "update": "go get -u ./src && go mod tidy" - }, - "keywords": [ - "exporter", - "immich", - "grafana", - "dashboard", - "metrics", - "prometheus" - ], - "author": "martabal", - "license": "MIT" -} diff --git a/src/immich/data.go b/src/immich/data.go index 571563f..910ac11 100644 --- a/src/immich/data.go +++ b/src/immich/data.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" "immich-exp/src/models" - "io/ioutil" + "io" "net/http" "sync" @@ -22,6 +22,28 @@ var ( mutex sync.Mutex ) +type Data struct { + URL string + HTTPMethod string +} + +var httpGetUsers = Data{ + URL: "/api/user?isAll=true", + HTTPMethod: http.MethodGet, +} +var httpServerVersion = Data{ + URL: "/api/server-info/version", + HTTPMethod: http.MethodGet, +} +var httpStatistics = Data{ + URL: "/api/server-info/statistics", + HTTPMethod: http.MethodGet, +} +var httpGetJobs = Data{ + URL: "/api/jobs", + HTTPMethod: http.MethodGet, +} + var unmarshalError = "Can not unmarshal JSON" func Allrequests(r *prometheus.Registry) { @@ -63,10 +85,10 @@ func Analyze(r *prometheus.Registry) { func GetAllUsers(c chan func() (*models.StructAllUsers, error)) { defer wg.Done() - resp, err := Apirequest("/api/user?isAll=true", "GET") + resp, err := Apirequest(httpGetUsers.URL, httpGetUsers.HTTPMethod) if err == nil { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } else { @@ -85,10 +107,10 @@ func GetAllUsers(c chan func() (*models.StructAllUsers, error)) { func ServerVersion(r *prometheus.Registry) { defer wg.Done() - resp, err := Apirequest("/api/server-info/version", "GET") + resp, err := Apirequest(httpServerVersion.URL, httpServerVersion.HTTPMethod) if err == nil { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } else { @@ -105,10 +127,10 @@ func ServerVersion(r *prometheus.Registry) { func ServerInfo(c chan func() (*models.StructServerInfo, error)) { defer wg.Done() - resp, err := Apirequest("/api/server-info/statistics", "GET") + resp, err := Apirequest(httpStatistics.URL, httpStatistics.HTTPMethod) if err == nil { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } else { @@ -126,10 +148,10 @@ func ServerInfo(c chan func() (*models.StructServerInfo, error)) { func GetAllJobsStatus(c chan func() (*models.StructAllJobsStatus, error)) { defer wg.Done() - resp, err := Apirequest("/api/jobs", "GET") + resp, err := Apirequest(httpGetJobs.URL, httpGetJobs.HTTPMethod) if err == nil { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } else { @@ -158,7 +180,7 @@ func Apirequest(uri string, method string) (*http.Response, error) { if err != nil { err := fmt.Errorf("Can't connect to server") mutex.Lock() - if models.GetPromptError() == false { + if !models.GetPromptError() { log.Error(err.Error()) models.SetPromptError(true) } @@ -175,17 +197,15 @@ func Apirequest(uri string, method string) (*http.Response, error) { mutex.Unlock() return resp, nil case http.StatusNotFound: - err := fmt.Errorf("%d", resp.StatusCode) log.Fatal("Error code ", resp.StatusCode, " for ", models.Getbaseurl()+uri) - return resp, err + return resp, fmt.Errorf("%d", resp.StatusCode) case http.StatusUnauthorized, http.StatusForbidden: - err := fmt.Errorf("%d", resp.StatusCode) log.Fatal("Api key unauthorized") - return resp, err + return resp, fmt.Errorf("%d", resp.StatusCode) default: err := fmt.Errorf("%d", resp.StatusCode) mutex.Lock() diff --git a/src/init.go b/src/init.go index eb9a2d4..07b3605 100644 --- a/src/init.go +++ b/src/init.go @@ -1,7 +1,6 @@ package main import ( - "encoding/json" "flag" "fmt" immich "immich-exp/src/immich" @@ -20,16 +19,24 @@ import ( ) const DEFAULTPORT = 8090 +const AUTHOR = "martabal" +const VERSION = "1.2.0" +const PROJECT_NAME = "immich-exporter" func main() { loadenv() - projectinfo() + fmt.Printf("%s (version %s)\n", PROJECT_NAME, VERSION) + fmt.Println("Author: ", AUTHOR) + fmt.Println("Using log level: ", log.GetLevel()) log.Info("Immich URL: ", models.Getbaseurl()) log.Info("Started") http.HandleFunc("/metrics", metrics) addr := ":" + strconv.Itoa(models.GetPort()) log.Info("Listening on port ", models.GetPort()) - http.ListenAndServe(addr, nil) + err := http.ListenAndServe(addr, nil) + if err != nil { + log.Fatalln(err) + } } func metrics(w http.ResponseWriter, r *http.Request) { @@ -40,25 +47,6 @@ func metrics(w http.ResponseWriter, r *http.Request) { h.ServeHTTP(w, r) } -func projectinfo() { - fileContent, err := os.ReadFile("./package.json") - if err != nil { - log.Fatal(err) - return - } - - var res map[string]interface{} - err = json.Unmarshal(fileContent, &res) - if err != nil { - log.Fatal(err) - return - } - - fmt.Print(res["name"], " (version ", res["version"], ")\n") - fmt.Print("Author: ", res["author"], "\n") - fmt.Print("Using log level: ", log.GetLevel(), "\n") -} - func loadenv() { var envfile bool flag.BoolVar(&envfile, "e", false, "Use .env file")