diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 688addbe..20b83ed2 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -21,6 +21,12 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '12.18.2' + - name: Configure AWS credentials from account + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-2 - uses: actions/checkout@v2 - name: Add GOBIN to PATH @@ -29,6 +35,13 @@ jobs: echo ::set-env name=VERSION::$(cat version.txt) shell: bash + - name: Font Awesome authentication + env: + FONTAWESOME_TOKEN: ${{ secrets.FONTAWESOME_TOKEN }} + run: | + npm config set "@fortawesome:registry" https://npm.fontawesome.com/ + npm config set "//npm.fontawesome.com/:_authToken" $FONTAWESOME_TOKEN + - name: Install Global Dependencies run: npm install -g yarn sass cross-env @@ -53,6 +66,12 @@ jobs: name: static-rice-box path: ./source + - name: Upload Assets to S3 + run: | + tar -czvf source.tar.gz source/ + aws s3 cp source.tar.gz s3://assets.statping.com/ + rm -rf source.tar.gz + test: needs: compile runs-on: ubuntu-latest @@ -116,6 +135,7 @@ jobs: gotestsum --no-summary=skipped --format dots -- -covermode=count -coverprofile=coverage.out -p=1 ./... env: VERSION: ${{ env.VERSION }} + COMMIT: ${{ github.sha }} DB_CONN: sqlite3 STATPING_DIR: ${{ github.workspace }} API_SECRET: demopassword123 @@ -231,6 +251,8 @@ jobs: - name: Install Statping env: VERSION: ${{ env.VERSION }} + MJML_APP: ${{ secrets.MJML_APP }} + MJML_PRIVATE: ${{ secrets.MJML_PRIVATE }} run: | make build chmod +x statping @@ -287,6 +309,7 @@ jobs: - name: Install Statping env: VERSION: ${{ env.VERSION }} + COMMIT: ${{ github.sha }} run: | make build chmod +x statping @@ -359,7 +382,9 @@ jobs: - name: Build Binaries env: VERSION: ${{ env.VERSION }} - COMMIT: $GITHUB_SHA + COMMIT: ${{ github.sha }} + MJML_APP: ${{ secrets.MJML_APP }} + MJML_PRIVATE: ${{ secrets.MJML_PRIVATE }} run: make build-folders build-linux build-linux-arm build-darwin build-win compress-folders docker-release: @@ -392,7 +417,13 @@ jobs: buildx-docker-master - name: Docker Build :base + env: + VERSION: ${{ env.VERSION }} + COMMIT: ${{ github.sha }} run: make buildx-base - name: Docker Build :dev + env: + VERSION: ${{ env.VERSION }} + COMMIT: ${{ github.sha }} run: make buildx-dev diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index f20aa940..52afd36d 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -16,6 +16,12 @@ jobs: - uses: actions/setup-node@v1 with: node-version: '12.18.2' + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-west-2 - uses: actions/checkout@v2 - name: Add GOBIN to PATH @@ -24,6 +30,13 @@ jobs: echo ::set-env name=VERSION::$(cat version.txt) shell: bash + - name: Font Awesome authentication + env: + FONTAWESOME_TOKEN: ${{ secrets.FONTAWESOME_TOKEN }} + run: | + npm config set "@fortawesome:registry" https://npm.fontawesome.com/ + npm config set "//npm.fontawesome.com/:_authToken" $FONTAWESOME_TOKEN + - name: Install Global Dependencies run: npm install -g yarn sass cross-env @@ -48,6 +61,19 @@ jobs: name: static-rice-box path: ./source + - name: Upload Assets to S3 + run: | + tar -czvf source.tar.gz source/ + cp source.tar.gz source-${VERSION}.tar.gz + aws s3 cp source.tar.gz s3://assets.statping.com/ + aws s3 cp source-${VERSION}.tar.gz s3://assets.statping.com/ + rm -rf source.tar.gz + rm -rf source-${VERSION}.tar.gz + aws s3 cp source/dist/css/ s3://assets.statping.com/css/ --recursive + aws s3 cp source/dist/js/ s3://assets.statping.com/js/ --recursive + aws s3 cp source/dist/scss/ s3://assets.statping.com/scss/ --recursive + aws s3 cp install.sh s3://assets.statping.com/ + test: needs: compile runs-on: ubuntu-latest @@ -226,6 +252,8 @@ jobs: - name: Install Statping env: VERSION: ${{ env.VERSION }} + MJML_APP: ${{ secrets.MJML_APP }} + MJML_PRIVATE: ${{ secrets.MJML_PRIVATE }} run: | make build chmod +x statping @@ -355,6 +383,8 @@ jobs: env: VERSION: ${{ env.VERSION }} COMMIT: $GITHUB_SHA + MJML_APP: ${{ secrets.MJML_APP }} + MJML_PRIVATE: ${{ secrets.MJML_PRIVATE }} run: make build-folders build-linux build-linux-arm build-darwin build-win compress-folders - name: Upload Builds @@ -434,9 +464,15 @@ jobs: buildx-docker - name: Docker Build :base + env: + VERSION: ${{ env.VERSION }} + COMMIT: ${{ github.sha }} run: make buildx-base - name: Docker Build :lastest + env: + VERSION: ${{ env.VERSION }} + COMMIT: ${{ github.sha }} run: make buildx-latest sentry-release: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 7cf5c6c8..d5a96c5e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -25,6 +25,13 @@ jobs: echo ::set-env name=VERSION::$(cat version.txt) shell: bash + - name: Font Awesome authentication + env: + FONTAWESOME_TOKEN: ${{ secrets.FONTAWESOME_TOKEN }} + run: | + npm config set "@fortawesome:registry" https://npm.fontawesome.com/ + npm config set "//npm.fontawesome.com/:_authToken" $FONTAWESOME_TOKEN + - name: Install Global Dependencies run: npm install -g yarn sass cross-env diff --git a/CHANGELOG.md b/CHANGELOG.md index 42f4efca..7393b3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +# 0.90.62 (08-07-2020) +- Added Notification logs +- Fixed issues with Notifer After (x) failures for notifications +- Modified notifications to not send on initial startup +- Updated Incident UI +- Added additional testing for notifications +- Modified SCSS/SASS files to be generated from 1, main.scss to main.css +- Modified index page to use /assets directory for assets, (main.css, style.css) +- Modified index page to use CDN asset paths +- Fixed New Checkin form +- Modified email notifier template to be rendered from MJML (using go generate) +- Modified database relationships with services using gorm +- Modified "statping env" command to show user/group ID +- Removed "js" folder when exporting assets, js files are always version of release, not static JS files + # 0.90.61 (07-22-2020) - Modified sass layouts, organized and split up sections - Modified Checkins to seconds rather than milliseconds (for cronjob) diff --git a/CloudronManifest.json b/CloudronManifest.json new file mode 100644 index 00000000..7ae27752 --- /dev/null +++ b/CloudronManifest.json @@ -0,0 +1,19 @@ +{ + "id": "com.statping", + "title": "Statping", + "author": "Hunter Long ", + "description": "Monitor your web services and remote servers", + "tagline": "Server Monitoring", + "version": "0.90.61", + "healthCheckPath": "/health", + "httpPort": 8080, + "addons": { + "localstorage": {} + }, + "manifestVersion": 2, + "website": "https://github.com/statping/statping", + "contactEmail": "info@statping.com", + "icon": "https://assets.statping.com/icon.png", + "tags": [ "monitoring", "uptime" ], + "mediaLinks": [ "https://assets.statping.com/cloudron.png" ] +}s diff --git a/Dockerfile.base b/Dockerfile.base index d90888ce..44c8ccb5 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -13,6 +13,7 @@ RUN yarn build && yarn cache clean FROM golang:1.14-alpine AS backend LABEL maintainer="Hunter Long (https://github.com/hunterlong)" ARG VERSION +ARG COMMIT ARG BUILDPLATFORM ARG TARGETARCH RUN apk add --update --no-cache libstdc++ gcc g++ make git autoconf \ @@ -36,8 +37,8 @@ RUN go get github.com/stretchr/testify/assert && \ go get github.com/crazy-max/xgo COPY . . COPY --from=frontend /statping/dist/ ./source/dist/ -RUN make clean frontend-copy generate embed -RUN GOOS=linux GOARCH=$TARGETARCH go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION}" -o statping --tags "netgo linux" ./cmd +RUN make clean generate embed +RUN go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION} -X main.COMMIT=${COMMIT}" -o statping --tags "netgo linux" ./cmd RUN chmod a+x statping && mv statping /go/bin/statping # /go/bin/statping - statping binary # /root/sassc/bin/sassc - sass binary diff --git a/Makefile b/Makefile index fde732d3..0ac5d982 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,12 @@ VERSION=$(shell cat version.txt) +COMMIT=$(shell git rev-parse HEAD) SIGN_KEY=B76D61FAA6DB759466E83D9964B9C6AAE2D55278 BINARY_NAME=statping GOBUILD=go build -a GOVERSION=1.14.0 NODE_VERSION=12.18.2 XGO=xgo -go $(GOVERSION) --dest=build -BUILDVERSION=-ldflags "-X main.VERSION=${VERSION}" +BUILDVERSION=-ldflags "-X main.VERSION=${VERSION} -X main.COMMIT=${COMMIT}" TRVIS_SECRET=O3/2KTOV8krv+yZ1EB/7D1RQRe6NdpFUEJNJkMS/ollYqmz3x2mCO7yIgIJKCKguLXZxjM6CxJcjlCrvUwibL+8BBp7xJe4XFIOrjkPvbbVPry4HkFZCf2GfcUK6o4AByQ+RYqsW2F17Fp9KLQ1rL3OT3eLTwCAGKx3tlY8y+an43zkmo5dN64V6sawx26fh6XTfww590ey+ltgQTjf8UPNup2wZmGvMo9Hwvh/bYR/47bR6PlBh6vhlKWyotKf2Fz1Bevbu0zc35pee5YlsrHR+oSF+/nNd/dOij34BhtqQikUR+zQVy9yty8SlmneVwD3yOENvlF+8roeKIXb6P6eZnSMHvelhWpAFTwDXq2N3d/FIgrQtLxsAFTI3nTHvZgs6OoTd6dA0wkhuIGLxaL3FOeztCdxP5J/CQ9GUcTvifh5ArGGwYxRxQU6rTgtebJcNtXFISP9CEUR6rwRtb6ax7h6f1SbjUGAdxt+r2LbEVEk4ZlwHvdJ2DtzJHT5DQtLrqq/CTUgJ8SJFMkrJMp/pPznKhzN4qvd8oQJXygSXX/gz92MvoX0xgpNeLsUdAn+PL9KketfR+QYosBz04d8k05E+aTqGaU7FUCHPTLwlOFvLD8Gbv0zsC/PWgSLXTBlcqLEz5PHwPVHTcVzspKj/IyYimXpCSbvu1YOIjyc= PUBLISH_BODY='{ "request": { "branch": "master", "message": "Homebrew update version v${VERSION}", "config": { "env": { "VERSION": "${VERSION}", "COMMIT": "$(TRAVIS_COMMIT)" } } } }' TRAVIS_BUILD_CMD='{ "request": { "branch": "master", "message": "Compile master for Statping v${VERSION}", "config": { "merge_mode": "replace", "language": "go", "go": 1.14, "install": true, "sudo": "required", "services": ["docker"], "env": { "secure": "${TRVIS_SECRET}" }, "before_deploy": ["git config --local user.name \"hunterlong\"", "git config --local user.email \"info@socialeck.com\"", "git tag v$(VERSION) --force"], "deploy": [{ "provider": "releases", "api_key": "$$GITHUB_TOKEN", "file_glob": true, "file": "build/*", "skip_cleanup": true, "on": { "branch": "master" } }], "before_script": ["rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install stable", "nvm install 10.17.0", "nvm use 10.17.0 --default", "npm install -g sass yarn cross-env", "pip install --user awscli"], "script": ["make release"], "after_success": [], "after_deploy": ["make post-release"] } } }' @@ -17,10 +18,23 @@ ARCHS = 386 arm amd64 arm64 all: build-deps compile install test build test: clean compile - go test -v -p=1 -ldflags="-X main.VERSION=0.99.99" -coverprofile=coverage.out ./... + go test -v -p=1 -ldflags="-X main.VERSION=${VERSION} -X main.COMMIT=${COMMIT}" -coverprofile=coverage.out ./... build: clean - go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION}" -o statping --tags "netgo linux" ./cmd + go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION} -X main.COMMIT=${COMMIT}" -o statping --tags "netgo linux" ./cmd + +go-build: clean + rm -rf source/dist + rm -rf source/rice-box.go + wget https://assets.statping.com/source.tar.gz + tar -xvf source.tar.gz + go build -a -ldflags "-s -w -extldflags -static -X main.VERSION=${VERSION} -X main.COMMIT=${COMMIT}" -o statping --tags "netgo" ./cmd + +lint: + go fmt ./... + golint ./... + impi --local github.com/statping/statping/ --scheme stdLocalThirdParty ./... + goimports ./... up: docker-compose -f docker-compose.yml -f dev/docker-compose.full.yml up -d --remove-orphans @@ -54,7 +68,7 @@ cypress: clean test-api: DB_CONN=sqlite DB_HOST=localhost DB_DATABASE=sqlite DB_PASS=none DB_USER=none statping & - sleep 5000 && newman run source/tmpl/postman.json -e dev/postman_environment.json --delay-request 500 + sleep 5000 && newman run dev/postman.json -e dev/postman_environment.json --delay-request 500 test-deps: go get golang.org/x/tools/cmd/cover @@ -129,14 +143,14 @@ frontend-build: @rm -rf source/dist && rm -rf frontend/dist @echo "yarn install and build static frontend" cd frontend && yarn && yarn build - @cp -r frontend/dist source/ && cp -r frontend/src/assets/scss source/dist/ - @cp -r source/tmpl/*.* source/dist/ + @cp -r frontend/dist source/ + @cp -r frontend/src/assets/scss source/dist/ + @cp frontend/public/favicon.ico source/dist/ + @cp frontend/public/robots.txt source/dist/ + @cp frontend/public/banner.png source/dist/ @cp -r frontend/public/favicon source/dist/ @echo "Frontend build complete at ./source/dist" -frontend-copy: - cp -r source/tmpl/*.* source/dist/ - yarn: rm -rf source/dist && rm -rf frontend/dist cd frontend && yarn @@ -145,6 +159,7 @@ yarn: compile: frontend-build rm -f source/rice-box.go cd source && rice embed-go + make generate embed: cd source && rice embed-go @@ -155,8 +170,12 @@ install: build install-local: build mv $(BINARY_NAME) /usr/local/bin/$(BINARY_NAME) +install-darwin: + go build -a -ldflags "-X main.VERSION=${VERSION}" -o statping --tags "netgo darwin" ./cmd + mv $(BINARY_NAME) /usr/local/bin/$(BINARY_NAME) + generate: - cd source && go generate + go generate ./... build-all: clean compile build-folders build-linux build-linux-arm build-darwin build-win compress-folders @@ -291,11 +310,14 @@ post-release: frontend-build upload_to_s3 publish-homebrew dockerhub publish-homebrew: curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token $(TRAVIS_API)" -d $(PUBLISH_BODY) https://api.travis-ci.com/repo/statping%2Fhomebrew-statping/requests -upload_to_s3: travis_s3_creds - aws s3 cp ./source/dist/css $(ASSETS_BKT) --recursive --exclude "*" --include "*.css" - aws s3 cp ./source/dist/js $(ASSETS_BKT) --recursive --exclude "*" --include "*.js" - aws s3 cp ./source/dist/scss $(ASSETS_BKT) --recursive --exclude "*" --include "*.scss" - aws s3 cp ./install.sh $(ASSETS_BKT) +upload_to_s3: + tar -czvf source.tar.gz source/ + aws s3 cp source.tar.gz s3://assets.statping.com/ + rm -rf source.tar.gz + aws s3 cp source/dist/css/ s3://assets.statping.com/css/ --recursive --exclude "*" --include "*.css" + aws s3 cp source/dist/js/ s3://assets.statping.com/js/ --recursive --exclude "*" --include "*.js" + aws s3 cp source/dist/scss/ s3://assets.statping.com/scss/ --recursive --exclude "*" --include "*.scss" + aws s3 cp install.sh s3://assets.statping.com/ travis_s3_creds: mkdir -p ~/.aws @@ -357,25 +379,29 @@ certs: buildx-latest: multiarch docker buildx create --name statping-latest docker buildx inspect --builder statping-latest --bootstrap - docker buildx build --builder statping-latest --cache-from "type=local,src=/tmp/.buildx-cache" --cache-to "type=local,dest=/tmp/.buildx-cache" --pull --push --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -f Dockerfile -t statping/statping:latest -t statping/statping:v${VERSION} --build-arg=VERSION=${VERSION} . + docker buildx build --builder statping-latest --cache-from "type=local,src=/tmp/.buildx-cache" --cache-to "type=local,dest=/tmp/.buildx-cache" --pull --push --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -f Dockerfile -t statping/statping:latest -t statping/statping:v${VERSION} --build-arg=VERSION=${VERSION} --build-arg=COMMIT=${COMMIT} . docker buildx rm statping-latest buildx-dev: multiarch docker buildx create --name statping-dev docker buildx inspect --builder statping-dev --bootstrap - docker buildx build --builder statping-dev --cache-from "type=local,src=/tmp/.buildx-cache" --cache-to "type=local,dest=/tmp/.buildx-cache" --pull --push --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -f Dockerfile -t statping/statping:dev --build-arg=VERSION=${VERSION} . + docker buildx build --builder statping-dev --cache-from "type=local,src=/tmp/.buildx-cache" --cache-to "type=local,dest=/tmp/.buildx-cache" --pull --push --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -f Dockerfile -t statping/statping:dev --build-arg=VERSION=${VERSION} --build-arg=COMMIT=${COMMIT} . docker buildx rm statping-dev buildx-base: multiarch docker buildx create --name statping-base docker buildx inspect --builder statping-base --bootstrap - docker buildx build --builder statping-base --cache-from "type=local,src=/tmp/.buildx-cache" --cache-to "type=local,dest=/tmp/.buildx-cache" --pull --push --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -f Dockerfile.base -t statping/statping:base --build-arg=VERSION=${VERSION} . + docker buildx build --builder statping-base --cache-from "type=local,src=/tmp/.buildx-cache" --cache-to "type=local,dest=/tmp/.buildx-cache" --pull --push --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6 -f Dockerfile.base -t statping/statping:base --build-arg=VERSION=${VERSION} --build-arg=COMMIT=${COMMIT} . docker buildx rm statping-base multiarch: mkdir /tmp/.buildx-cache || true docker run --rm --privileged multiarch/qemu-user-static --reset -p yes +delve: + go build -gcflags "all=-N -l" -o statping ./cmd + dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./statping + check: @echo "Checking the programs required for the build are installed..." @echo "go: $(shell go version) - $(shell which go)" && go version >/dev/null 2>&1 || (echo "ERROR: go 1.14 is required."; exit 1) @@ -383,5 +409,5 @@ check: @echo "yarn: $(shell yarn --version) - $(shell which yarn)" && yarn --version >/dev/null 2>&1 || (echo "ERROR: yarn is required."; exit 1) @echo "All required programs are installed!" -.PHONY: all check build certs multiarch build-all buildx-base buildx-dev buildx-latest build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman +.PHONY: all check build certs multiarch install-darwin go-build build-all buildx-base buildx-dev buildx-latest build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman .SILENT: travis_s3_creds diff --git a/app.json b/app.json index 6d73c60d..a4f0abfb 100644 --- a/app.json +++ b/app.json @@ -2,6 +2,6 @@ "name": "Statping", "description": "Statping Server Monitoring with Status Page", "repository": "https://github.com/statping/statping", - "logo": "https://raw.githubusercontent.com/statping/statping/master/source/tmpl/banner.png", + "logo": "https://assets.statping.com/banner.png", "keywords": ["statping", "server", "monitoring", "status page","golang", "go"] } diff --git a/cmd/cli.go b/cmd/cli.go index 389b0ca4..5125433f 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -16,6 +16,7 @@ import ( "github.com/statping/statping/utils" "io/ioutil" "os" + "path/filepath" "strings" "time" ) @@ -34,13 +35,77 @@ func assetsCli() error { return nil } -func systemctlCli() error { - fmt.Println("still in the works...") +func systemctlCli(dir string, uninstall bool, port int64) error { + location := "/etc/systemd/system/statping.service" + + if uninstall { + fmt.Println("systemctl stop statping") + if _, _, err := utils.Command("systemctl", "stop", "statping"); err != nil { + log.Errorln(err) + } + fmt.Println("systemctl disable statping") + if _, _, err := utils.Command("systemctl", "disable", "statping"); err != nil { + log.Errorln(err) + } + fmt.Println("Deleting systemctl: ", location) + if err := utils.DeleteFile(location); err != nil { + log.Errorln(err) + } + return nil + } + if ok := utils.FolderExists(dir); !ok { + return errors.New("directory does not exist: " + dir) + } + + binPath, err := os.Executable() + if err != nil { + return err + } + + config := []byte(`[Unit] +Description=Statping Server +After=network.target +After=systemd-user-sessions.service +After=network-online.target + +[Service] +Type=simple +Restart=always +Environment="STATPING_DIR=` + dir + `" +Environment="ALLOW_REPORTS=true" +ExecStart=` + binPath + ` --port=` + utils.ToString(port) + ` +WorkingDirectory=` + dir + ` + +[Install] +WantedBy=multi-user.target" +`) + fmt.Println("Saving systemctl service to: ", location) + fmt.Printf("Using directory %s for Statping data\n", dir) + fmt.Printf("Running on port %d\n", port) + fmt.Printf("\n\n%s\n\n", string(config)) + if err := utils.SaveFile(location, config); err != nil { + return err + } + fmt.Println("systemctl daemon-reload") + if _, _, err := utils.Command("systemctl", "daemon-reload"); err != nil { + return err + } + fmt.Println("systemctl enable statping") + if _, _, err := utils.Command("systemctl", "enable", "statping.service"); err != nil { + return err + } + fmt.Println("systemctl start statping") + if _, _, err := utils.Command("systemctl", "start", "statping"); err != nil { + return err + } + fmt.Println("Statping was will auto start on reboots") + fmt.Println("systemctl service: ", location) + return nil } func exportCli(args []string) error { - filename := fmt.Sprintf("%s/statping-%s.json", utils.Directory, time.Now().Format("01-02-2006-1504")) + filename := filepath.Join(utils.Directory, time.Now().Format("01-02-2006-1504")+".json") if len(args) == 1 { filename = fmt.Sprintf("%s/%s", utils.Directory, args) } @@ -78,7 +143,7 @@ func sassCli() error { if err := source.Assets(); err != nil { return err } - if err := source.CompileSASS(source.DefaultScss...); err != nil { + if err := source.CompileSASS(); err != nil { return err } return nil @@ -133,6 +198,10 @@ func resetCli() error { func envCli() error { fmt.Println("Statping Configuration") + fmt.Printf("Process ID: %d\n", os.Getpid()) + fmt.Printf("Running as user id: %d\n", os.Getuid()) + fmt.Printf("Running as group id: %d\n", os.Getgid()) + fmt.Printf("Statping Directory: %s\n", utils.Directory) for k, v := range utils.Params.AllSettings() { fmt.Printf("%s=%v\n", strings.ToUpper(k), v) } diff --git a/cmd/cli_test.go b/cmd/cli_test.go index 94de537d..586db178 100644 --- a/cmd/cli_test.go +++ b/cmd/cli_test.go @@ -2,10 +2,12 @@ package main import ( "bytes" + "github.com/statping/statping/source" "github.com/statping/statping/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "io/ioutil" + "os" "testing" ) @@ -18,16 +20,15 @@ func init() { } func TestStatpingDirectory(t *testing.T) { - dir := utils.Directory - require.NotContains(t, dir, "/cmd") - require.NotEmpty(t, dir) - dir = utils.Params.GetString("STATPING_DIR") require.NotContains(t, dir, "/cmd") require.NotEmpty(t, dir) } func TestEnvCLI(t *testing.T) { + os.Setenv("API_SECRET", "demoapisecret123") + os.Setenv("SASS", "/usr/local/bin/sass") + cmd := rootCmd b := bytes.NewBufferString("") cmd.SetOut(b) @@ -39,6 +40,12 @@ func TestEnvCLI(t *testing.T) { assert.Contains(t, string(out), VERSION) assert.Contains(t, utils.Directory, string(out)) assert.Contains(t, "SAMPLE_DATA=true", string(out)) + assert.Contains(t, "API_SECRET=demoapisecret123", string(out)) + assert.Contains(t, "STATPING_DIR="+dir, string(out)) + assert.Contains(t, "SASS=/usr/local/bin/sass", string(out)) + + os.Unsetenv("API_SECRET") + os.Unsetenv("SASS") } func TestVersionCLI(t *testing.T) { @@ -58,16 +65,26 @@ func TestAssetsCLI(t *testing.T) { b := bytes.NewBufferString("") cmd.SetOut(b) cmd.SetArgs([]string{"assets"}) - cmd.Execute() + err := cmd.Execute() + require.Nil(t, err) out, err := ioutil.ReadAll(b) assert.Nil(t, err) assert.Contains(t, string(out), VERSION) - assert.FileExists(t, utils.Directory+"/assets/css/main.css") - assert.FileExists(t, utils.Directory+"/assets/css/style.css") - assert.FileExists(t, utils.Directory+"/assets/css/vendor.css") - assert.FileExists(t, utils.Directory+"/assets/scss/base.scss") - assert.FileExists(t, utils.Directory+"/assets/scss/mobile.scss") - assert.FileExists(t, utils.Directory+"/assets/scss/variables.scss") + for _, f := range source.RequiredFiles { + assert.FileExists(t, utils.Directory+"/assets/"+f) + } +} + +func TestUpdateCLI(t *testing.T) { + cmd := rootCmd + b := bytes.NewBufferString("") + cmd.SetOut(b) + cmd.SetArgs([]string{"update"}) + err := cmd.Execute() + require.Nil(t, err) + out, err := ioutil.ReadAll(b) + require.Nil(t, err) + assert.Contains(t, string(out), VERSION) } func TestHelpCLI(t *testing.T) { diff --git a/cmd/commands.go b/cmd/commands.go index b9609115..b2850854 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -5,24 +5,28 @@ import ( "fmt" "github.com/pkg/errors" "github.com/spf13/cobra" + "github.com/statping/statping/utils" "io" "os" "os/exec" ) var rootCmd = &cobra.Command{ - Use: "statping", - Short: "A simple Application Status Monitor that is opensource and lightweight.", + Use: "statping", + Version: VERSION, + Short: "A simple Application Status Monitor that is opensource and lightweight.", Run: func(cmd *cobra.Command, args []string) { start() }, } var updateCmd = &cobra.Command{ - Use: "update", - Short: "Update to the latest version", + Use: "update", + Example: "statping update", + Short: "Update to the latest version", RunE: func(cmd *cobra.Command, args []string) error { log.Infoln("Updating Statping to the latest version...") + log.Infoln("curl -o- -L https://statping.com/install.sh | bash") curl, err := exec.LookPath("curl") if err != nil { return err @@ -58,8 +62,9 @@ var updateCmd = &cobra.Command{ } var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the version number of Statping", + Use: "version", + Example: "statping version", + Short: "Print the version number of Statping", Run: func(cmd *cobra.Command, args []string) { if COMMIT != "" { fmt.Printf("%s (%s)\n", VERSION, COMMIT) @@ -71,26 +76,37 @@ var versionCmd = &cobra.Command{ } var systemctlCmd = &cobra.Command{ - Use: "systemctl [install/uninstall]", - Short: "Install or Uninstall systemctl links", + Use: "systemctl [install/uninstall]", + Example: "statping systemctl install", + Short: "Install or Uninstall systemctl services", RunE: func(cmd *cobra.Command, args []string) error { - if err := systemctlCli(); err != nil { + if args[1] == "install" { + if len(args) < 3 { + return errors.New("requires 'install '") + } + } + port := utils.ToInt(args[2]) + if port == 0 { + port = 80 + } + if err := systemctlCli(args[1], args[0] == "uninstall", port); err != nil { return err } os.Exit(0) return nil }, Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return errors.New("requires 'install' or 'uninstall' as arguments") + if len(args) < 2 { + return errors.New("requires 'install ' or 'uninstall' as arguments") } return nil }, } var assetsCmd = &cobra.Command{ - Use: "assets", - Short: "Dump all assets used locally to be edited", + Use: "assets", + Example: "statping assets", + Short: "Dump all assets used locally to be edited", RunE: func(cmd *cobra.Command, args []string) error { if err := assetsCli(); err != nil { return err @@ -101,8 +117,9 @@ var assetsCmd = &cobra.Command{ } var exportCmd = &cobra.Command{ - Use: "export", - Short: "Exports your Statping settings to a 'statping-export.json' file.", + Use: "export", + Example: "statping export", + Short: "Exports your Statping settings to a 'statping-export.json' file.", RunE: func(cmd *cobra.Command, args []string) error { if err := exportCli(args); err != nil { return err @@ -113,8 +130,9 @@ var exportCmd = &cobra.Command{ } var sassCmd = &cobra.Command{ - Use: "sass", - Short: "Compile .scss files into the css directory", + Use: "sass", + Example: "statping sass", + Short: "Compile .scss files into the css directory", RunE: func(cmd *cobra.Command, args []string) error { if err := sassCli(); err != nil { return err @@ -125,8 +143,9 @@ var sassCmd = &cobra.Command{ } var envCmd = &cobra.Command{ - Use: "env", - Short: "Return the configs that will be ran", + Use: "env", + Example: "statping env", + Short: "Return the configs that will be ran", RunE: func(cmd *cobra.Command, args []string) error { if err := envCli(); err != nil { return err @@ -137,8 +156,9 @@ var envCmd = &cobra.Command{ } var resetCmd = &cobra.Command{ - Use: "reset", - Short: "Start a fresh copy of Statping", + Use: "reset", + Example: "statping reset", + Short: "Start a fresh copy of Statping", RunE: func(cmd *cobra.Command, args []string) error { if err := resetCli(); err != nil { return err @@ -149,8 +169,9 @@ var resetCmd = &cobra.Command{ } var onceCmd = &cobra.Command{ - Use: "once", - Short: "Check all services 1 time and then quit", + Use: "once", + Example: "statping once", + Short: "Check all services 1 time and then quit", RunE: func(cmd *cobra.Command, args []string) error { if err := onceCli(); err != nil { return err @@ -161,8 +182,9 @@ var onceCmd = &cobra.Command{ } var importCmd = &cobra.Command{ - Use: "import [.json file]", - Short: "Imports settings from a previously saved JSON file.", + Use: "import [.json file]", + Example: "statping import backup.json", + Short: "Imports settings from a previously saved JSON file.", RunE: func(cmd *cobra.Command, args []string) error { if err := importCli(args); err != nil { return err diff --git a/database/grouping.go b/database/grouping.go index 54544870..6d982a3b 100644 --- a/database/grouping.go +++ b/database/grouping.go @@ -39,7 +39,7 @@ type GroupQuery struct { } func (b GroupQuery) Find(data interface{}) error { - return b.db.Find(data).Error() + return b.db.Order("id DESC").Find(data).Error() } func (b GroupQuery) Database() Database { diff --git a/dev/postman.json b/dev/postman.json index 37f6c38a..17798522 100644 --- a/dev/postman.json +++ b/dev/postman.json @@ -3275,6 +3275,8 @@ "pm.test(\"Check Login JWT Token\", function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData).to.have.property('token');", + " pm.expect(jsonData).to.have.property('admin');", + " pm.globals.set(\"token\", jsonData.token);", "});" ], "type": "text/javascript" @@ -3371,24 +3373,141 @@ "_postman_previewlanguage": "json", "header": [ { - "key": "Content-Length", - "value": "174" + "key": "Content-Type", + "value": "application/json" }, + { + "key": "Set-Cookie", + "value": "statping_auth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInNjb3BlcyI6ImFkbWluIiwiZXhwIjoxNTk2NzQzMDUzfQ.dQQGgUDhFEjCL2Gi-Seg0hBp_sqVsDn3cXB0GpSorJI; Path=/; Expires=Thu, 06 Aug 2020 19:44:13 GMT; Max-Age=259200" + }, + { + "key": "Date", + "value": "Mon, 03 Aug 2020 19:44:13 GMT" + }, + { + "key": "Content-Length", + "value": "197" + }, + { + "key": "Connection", + "value": "close" + } + ], + "cookie": [], + "body": "{\n \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsInNjb3BlcyI6ImFkbWluIiwiZXhwIjoxNTk2NzQzMDUzfQ.dQQGgUDhFEjCL2Gi-Seg0hBp_sqVsDn3cXB0GpSorJI\",\n \"admin\": true\n}" + } + ] + }, + { + "name": "Check User Token", + "event": [ + { + "listen": "test", + "script": { + "id": "560e439b-d588-4a2f-a8a6-a0607531d74c", + "exec": [ + "pm.test(\"Response is ok\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"View Token Response\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.username).to.eql(\"admin\");", + " pm.expect(jsonData.admin).to.eql(true);", + " pm.expect(jsonData.scopes).to.eql(\"admin\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{api_key}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "token", + "value": "{{token}}", + "type": "text" + } + ] + }, + "url": { + "raw": "{{endpoint}}/api/users/token", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "users", + "token" + ] + }, + "description": "Send your JWT token from login to this endpoint to return the JSON values." + }, + "response": [ + { + "name": "Check User Token", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "token", + "value": "{{token}}", + "type": "text" + } + ] + }, + "url": { + "raw": "{{endpoint}}/api/users/token", + "host": [ + "{{endpoint}}" + ], + "path": [ + "api", + "users", + "token" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ { "key": "Content-Type", "value": "application/json" }, { "key": "Date", - "value": "Sat, 02 May 2020 00:56:17 GMT" + "value": "Mon, 03 Aug 2020 19:47:23 GMT" }, { - "key": "Set-Cookie", - "value": "statping_auth=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsImV4cCI6MTU4ODY0MDE3N30.tf399_LfAphSGlKMtgphg6qpPrn-_w92XfCrK5FwbZY; Expires=Tue, 05 May 2020 00:56:17 GMT" + "key": "Content-Length", + "value": "68" + }, + { + "key": "Connection", + "value": "close" } ], "cookie": [], - "body": "{\n \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOnRydWUsImV4cCI6MTU4ODY0MDE3N30.tf399_LfAphSGlKMtgphg6qpPrn-_w92XfCrK5FwbZY\",\n \"admin\": true\n}" + "body": "{\n \"username\": \"admin\",\n \"admin\": true,\n \"scopes\": \"admin\",\n \"exp\": 1596743053\n}" } ] }, diff --git a/frontend/config/webpack.config.prod.js b/frontend/config/webpack.config.prod.js index f181627b..d877196f 100644 --- a/frontend/config/webpack.config.prod.js +++ b/frontend/config/webpack.config.prod.js @@ -60,6 +60,9 @@ const webpackConfig = merge(commonConfig, { plugins: [ new webpack.EnvironmentPlugin(environment), new CleanWebpackPlugin(), + // new webpack.optimize.LimitChunkCountPlugin({ + // maxChunks: 1 + // }), new MiniCSSExtractPlugin({ filename: 'css/[name].css', chunkFilename: 'css/[name].css' diff --git a/frontend/package.json b/frontend/package.json index bba654ca..731eb014 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,14 +19,12 @@ "@fortawesome/free-brands-svg-icons": "^5.12.1", "@fortawesome/free-solid-svg-icons": "^5.12.0", "@fortawesome/vue-fontawesome": "^0.1.9", - "@sentry/browser": "^5.13.2", - "@sentry/integrations": "^5.13.2", + "@sentry/browser": "^5.20.1", + "@sentry/integrations": "^5.20.1", "apexcharts": "^3.15.0", "axios": "^0.19.1", - "bootstrap": "^4.4.1", - "bootstrap-vue": "^2.6.1", "codemirror-colorpicker": "^1.9.66", - "core-js": "^3.4.4", + "core-js": "^3.6.5", "date-fns": "^2.9.0", "js-beautify": "^1.11.0", "querystring": "^0.2.0", @@ -39,7 +37,6 @@ "vue-flatpickr-component": "^8.1.5", "vue-github-button": "^1.1.2", "vue-i18n": "^8.18.1", - "vue-moment": "^4.1.0", "vue-observe-visibility": "^0.4.6", "vue-router": "~3.0", "vuedraggable": "^2.23.2", diff --git a/frontend/public/base.gohtml b/frontend/public/base.gohtml index 07bf22ba..45ecbe3c 100644 --- a/frontend/public/base.gohtml +++ b/frontend/public/base.gohtml @@ -43,19 +43,11 @@ {{if USE_CDN}} - - - - {{else}} - {{if USING_ASSETS}} - - - + {{else}} <% _.each(htmlWebpackPlugin.tags.headTags, function(headTag) { %> <%= headTag %> <% }) %> {{end}} - {{end}}