diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml new file mode 100644 index 00000000000..ef73849aa75 --- /dev/null +++ b/.github/workflows/goreleaser.yml @@ -0,0 +1,58 @@ +name: Goreleaser +on: + pull_request: + +permissions: + contents: read + +concurrency: + group: ${{ github.head_ref || github.ref_name }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Check out source code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Set up Go + uses: actions/setup-go@v5.0.0 + with: + go-version: "1.21.5" + + - uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Test GoReleaser + uses: goreleaser/goreleaser-action@v5 + with: + version: v1.22.1 + args: release --skip=publish --snapshot + distribution: goreleaser + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Cinc (Inspec) + run: | + curl -L https://omnitruck.cinc.sh/install.sh | \ + sudo bash -s -- -P cinc-auditor -v 4 + + - name: Install Deb Package + run: | + sudo apt-get install -y -f ./dist/prometheus_linux_amd64.deb + sudo systemctl start prometheus + + - name: Test Install + run: sudo cinc-auditor exec package/test/install/test.rb + + - name: Uninstall Deb Package + run: | + sudo apt-get remove -y prometheus + sudo apt-get purge -y prometheus + + - name: Test Uninstall + run: sudo cinc-auditor exec package/test/uninstall/test.rb diff --git a/.gitignore b/.gitignore index e85d766b095..9953eef075f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ benchmark.txt !/.travis.yml !/.promu.yml !/.golangci.yml +!/.goreleaser.yml /documentation/examples/remote_storage/remote_storage_adapter/remote_storage_adapter /documentation/examples/remote_storage/example_write_adapter/example_write_adapter @@ -31,3 +32,5 @@ npm_licenses.tar.bz2 # Ignore parser debug y.output + +dist/ diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 00000000000..53d31442355 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,187 @@ +before: + hooks: + # See `make build` for list build prerequisites. + - make assets + - make npm_licenses + - make assets-compress + - make plugins + +builds: + - id: prometheus + binary: prometheus + main: ./cmd/prometheus + env: + - CGO_ENABLED=0 + mod_timestamp: "{{ .CommitTimestamp }}" + goos: + - linux + goarch: + - amd64 + - arm64 + flags: + - -tags=netgo,builtinassets,stringlabels + ldflags: + - -s -w + - -X github.com/prometheus/common/version.Version={{ .Version }} + - -X github.com/prometheus/common/version.Revision="" + - -X github.com/prometheus/common/version.Branch={{ .Branch }} + - -X github.com/prometheus/common/version.BuildUser=observIQ + - -X github.com/prometheus/common/version.BuildDate={{ .Date }} + no_unique_dist_dir: false + - id: promtool + binary: promtool + main: ./cmd/promtool + env: + - CGO_ENABLED=0 + mod_timestamp: "{{ .CommitTimestamp }}" + goos: + - linux + goarch: + - amd64 + - arm64 + flags: + - -tags=netgo,builtinassets,stringlabels + ldflags: + - -s -w + - -X github.com/prometheus/common/version.Version={{ .Version }} + - -X github.com/prometheus/common/version.Revision="" + - -X github.com/prometheus/common/version.Branch={{ .Branch }} + - -X github.com/prometheus/common/version.BuildUser=observIQ + - -X github.com/prometheus/common/version.BuildDate={{ .Date }} + no_unique_dist_dir: false + +nfpms: + - id: prometheus + file_name_template: "{{ .PackageName }}_{{ .Os }}_{{ .Arch }}" + package_name: prometheus + vendor: observIQ, Inc + maintainer: observIQ + description: The Prometheus monitoring system and time series database. + homepage: https://github.com/prometheus/prometheus + license: Apache 2.0 + builds: + - prometheus + - promtool + formats: + - rpm + - deb + bindir: /usr/bin + contents: + - dst: /var/lib/prometheus + type: dir + file_info: + owner: prometheus + group: prometheus + mode: 0750 + - dst: /var/lib/prometheus/console_libraries + type: dir + file_info: + owner: prometheus + group: prometheus + mode: 0750 + - dst: /var/lib/prometheus/consoles + type: dir + file_info: + owner: prometheus + group: prometheus + mode: 0750 + - dst: /var/lib/prometheus/tsdb + type: dir + file_info: + owner: prometheus + group: prometheus + mode: 0750 + - dst: /etc/prometheus + type: dir + file_info: + owner: prometheus + group: prometheus + mode: 0750 + - dst: /usr/share/doc/prometheus + type: dir + file_info: + owner: root + group: root + mode: 0755 + - src: package/service/prometheus.service + dst: /usr/lib/systemd/system/prometheus.service + type: "config" + file_info: + owner: root + group: root + mode: 0640 + - src: package/config/prometheus.yml + dst: /etc/prometheus/prometheus.yml + type: "config" + file_info: + owner: prometheus + group: prometheus + mode: 0640 + - src: package/config/web.yml + dst: /etc/prometheus/web.yml + type: "config" + file_info: + owner: prometheus + group: prometheus + mode: 0640 + - src: package/config/rules.yml + dst: /etc/prometheus/rules.yml + type: "config" + file_info: + owner: prometheus + group: prometheus + mode: 0640 + - src: console_libraries/* + dst: /var/lib/prometheus/console_libraries/ + type: "config" + file_info: + owner: prometheus + group: prometheus + mode: 0640 + - src: consoles/* + dst: /var/lib/prometheus/consoles/ + type: "config" + file_info: + owner: prometheus + group: prometheus + mode: 0640 + - src: NOTICE + dst: /usr/share/doc/prometheus/NOTICE + type: "config" + file_info: + owner: root + group: root + mode: 0644 + - src: LICENSE + dst: /usr/share/doc/prometheus/LICENSE + type: "config" + file_info: + owner: root + group: root + mode: 0644 + - src: npm_licenses.tar.bz2 + dst: /usr/share/doc/prometheus/npm_licenses.tar.bz2 + type: "config" + file_info: + owner: root + group: root + mode: 0644 + scripts: + preremove: package/scripts/preremove.sh + postremove: package/scripts/postremove.sh + preinstall: package/scripts/preinstall.sh + postinstall: package/scripts/postinstall.sh + +archives: + - format: tar.gz + id: prometheus + name_template: prometheus-{{ .Version }}.{{ .Os }}-{{ .Arch }} + builds: + - prometheus + +checksum: + name_template: "{{ .ProjectName }}-v{{ .Version }}-SHA256SUMS" + algorithm: sha256 + +release: + draft: false diff --git a/package/config/prometheus.yml b/package/config/prometheus.yml new file mode 100644 index 00000000000..249b1387b40 --- /dev/null +++ b/package/config/prometheus.yml @@ -0,0 +1,2 @@ +scrape_configs: [] +rule_files: [/etc/prometheus/rules.yml] diff --git a/package/config/rules.yml b/package/config/rules.yml new file mode 100644 index 00000000000..9caee22cde0 --- /dev/null +++ b/package/config/rules.yml @@ -0,0 +1,6 @@ +groups: +- name: configuration-rollups + interval: 1m + rules: + - record: bindplane_agent_measurements:rollup:rate:1m + expr: sum without (agent) (rate(bindplane_agent_measurements{}[1m] offset 10s)) diff --git a/package/config/web.yml b/package/config/web.yml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/package/scripts/postinstall.sh b/package/scripts/postinstall.sh new file mode 100644 index 00000000000..0c518bd6ed7 --- /dev/null +++ b/package/scripts/postinstall.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Install handles systemd service management. This function +# can be called more than once as it is idempotent. +install() { + systemctl daemon-reload +} + +# Upgrade performs the same steps as install. +upgrade() { + install +} + +action="$1" + +case "$action" in + "0" | "install") + install + ;; + "1" | "upgrade") + upgrade + ;; + *) + install + ;; +esac diff --git a/package/scripts/postremove.sh b/package/scripts/postremove.sh new file mode 100644 index 00000000000..985b6e8830c --- /dev/null +++ b/package/scripts/postremove.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -e + +# Remove deletes the prometheus systemd service file +# and reloads systemd. If the file does not exist, return early. +remove() { + rm -f /usr/lib/systemd/system/prometheus.service || return + systemctl daemon-reload +} + +# Upgrade performs a no-op and is included here for future use. +upgrade() { + return +} + +action="$1" + +case "$action" in + "0" | "remove") + remove + ;; + "1" | "upgrade") + upgrade + ;; + *) + remove + ;; +esac diff --git a/package/scripts/preinstall.sh b/package/scripts/preinstall.sh new file mode 100644 index 00000000000..b398768dd56 --- /dev/null +++ b/package/scripts/preinstall.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +set -e + +# Install creates the prometheus user and group using the +# name 'prometheus'. The prometheus user does not have a shell. +# This function can be called more than once as it is idempotent. +install() { + username="prometheus" + + if getent group "$username" &>/dev/null; then + echo "Group ${username} already exists." + else + groupadd "$username" + fi + + if id "$username" &>/dev/null; then + echo "User ${username} already exists" + exit 0 + else + useradd --shell /sbin/nologin --system "$username" -g "$username" + fi +} + +# Upgrade should perform the same steps as install +upgrade() { + install +} + +action="$1" + +case "$action" in + "0" | "install") + install + ;; + "1" | "upgrade") + upgrade + ;; + *) + install + ;; +esac diff --git a/package/scripts/preremove.sh b/package/scripts/preremove.sh new file mode 100644 index 00000000000..150ba568528 --- /dev/null +++ b/package/scripts/preremove.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -e + +# Remove stops and disables the prometheus service. +remove() { + if systemctl disable --now prometheus ; then + echo "Service stopped: prometheus" + echo "Service disabled: prometheus" + fi +} + +# Upgrade performs a no-op and is included here for future use. +upgrade() { + return +} + +action="$1" + +case "$action" in + "0" | "remove") + remove + ;; + "1" | "upgrade") + upgrade + ;; + *) + remove + ;; +esac diff --git a/package/service/prometheus.service b/package/service/prometheus.service new file mode 100644 index 00000000000..8212b81740a --- /dev/null +++ b/package/service/prometheus.service @@ -0,0 +1,21 @@ +[Unit] +Description=Prometheus +Documentation=https://prometheus.io/docs/introduction/overview/ +Wants=network-online.target +After=network-online.target +[Service] +User=prometheus +Group=prometheus +Type=simple +ExecStart=/usr/bin/prometheus \ +--config.file /etc/prometheus/prometheus.yml \ +--web.config.file /etc/prometheus/web.yml \ +--storage.tsdb.retention.time 2d \ +--web.enable-remote-write-receiver \ +--web.listen-address :9090 \ +--storage.tsdb.path /var/lib/prometheus/tsdb \ +--web.console.templates=/var/lib/prometheus/consoles \ +--web.console.libraries=/var/lib/prometheus/console_libraries + +[Install] +WantedBy=multi-user.target diff --git a/package/test/install/test.rb b/package/test/install/test.rb new file mode 100644 index 00000000000..50e0f964e3e --- /dev/null +++ b/package/test/install/test.rb @@ -0,0 +1,139 @@ +describe package('prometheus') do + it { should be_installed } +end + +[ + '/usr/bin/prometheus', + '/usr/bin/promtool', +].each do |bin| + describe file(bin) do + its('mode') { should cmp '0755' } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('type') { should cmp 'file' } + end +end + +describe file('/usr/lib/systemd/system/prometheus.service') do + its('mode') { should cmp '0640' } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('type') { should cmp 'file' } +end + +[ + '/etc/prometheus', + '/var/lib/prometheus', + '/var/lib/prometheus/console_libraries', + '/var/lib/prometheus/consoles', + '/var/lib/prometheus/tsdb', +].each do |dir| + describe file(dir) do + its('mode') { should cmp '0750' } + its('owner') { should eq 'prometheus' } + its('group') { should eq 'prometheus' } + its('type') { should cmp 'directory' } + end +end + +[ + '/etc/prometheus/prometheus.yml', + '/etc/prometheus/web.yml', + '/etc/prometheus/rules.yml', + '/var/lib/prometheus/consoles/node-overview.html', + '/var/lib/prometheus/consoles/node-disk.html', + '/var/lib/prometheus/consoles/node-cpu.html', + '/var/lib/prometheus/consoles/node.html', + '/var/lib/prometheus/consoles/prometheus.html', + '/var/lib/prometheus/consoles/index.html.example', + '/var/lib/prometheus/consoles/prometheus-overview.html', + '/var/lib/prometheus/console_libraries/menu.lib', + '/var/lib/prometheus/console_libraries/prom.lib' +].each do |config| + describe file(config) do + its('mode') { should cmp '0640' } + its('owner') { should eq 'prometheus' } + its('group') { should eq 'prometheus' } + its('type') { should cmp 'file' } + end +end + +describe file('/usr/share/doc/prometheus') do + its('mode') { should cmp '0755' } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('type') { should cmp 'directory' } +end + +[ + '/usr/share/doc/prometheus/NOTICE', + '/usr/share/doc/prometheus/LICENSE', + '/usr/share/doc/prometheus/npm_licenses.tar.bz2' +].each do |file| + describe file(file) do + its('mode') { should cmp '0644' } + its('owner') { should eq 'root' } + its('group') { should eq 'root' } + its('type') { should cmp 'file' } + end +end + +describe user('prometheus') do + it { should exist } + its('group') { should eq 'prometheus' } + its('lastlogin') { should eq nil } + its('shell') { should eq '/sbin/nologin' } +end + +describe group('prometheus') do + it { should exist } +end + +# After starting the service, the process should be running and +# allow these tests to pass. + +describe systemd_service('prometheus') do + it { should be_installed } + it { should_not be_enabled } +end + +# after starting Prometheus, these files and directories should +# be created and proves that the process has permission to write +# to the tsdb directory. +[ + '/var/lib/prometheus/tsdb/lock', + '/var/lib/prometheus/tsdb/queries.active', + '/var/lib/prometheus/tsdb/wal/00000000' +].each do |file| + describe file(file) do + its('mode') { should cmp '0644' } + its('owner') { should eq 'prometheus' } + its('group') { should eq 'prometheus' } + its('type') { should cmp 'file' } + end +end + +# Default install listens on all interfaces because +# it is intended to be used by remote bindplane +# instances. +describe port(9090) do + it { should be_listening } + its('protocols') { should include 'tcp' } + its('addresses') { should_not include '127.0.0.1' } + its('addresses') { should include '0.0.0.0' } + its('processes') {should include 'prometheus'} +end + +[ + 'http://localhost:9090/graph', + 'http://localhost:9090/metrics', + 'http://localhost:9090/status' +].each do |url| + describe http(url) do + its('status') { should cmp 200 } + end +end + +describe processes('prometheus') do + its('users') { should eq ['prometheus'] } +end diff --git a/package/test/uninstall/test.rb b/package/test/uninstall/test.rb new file mode 100644 index 00000000000..dece12b3226 --- /dev/null +++ b/package/test/uninstall/test.rb @@ -0,0 +1,92 @@ +describe package('prometheus') do + it { should_not be_installed } +end + +[ + '/usr/bin/prometheus', + '/usr/bin/promtool', +].each do |bin| + describe file(bin) do + it { should_not exist } + end +end + +describe file('/usr/lib/systemd/system/prometheus.service') do + it { should_not exist } +end + +[ + '/etc/prometheus', + '/var/lib/prometheus/console_libraries', + '/var/lib/prometheus/consoles', +].each do |dir| + describe file(dir) do + it { should_not exist } + end +end + +# Won't get cleaned up to do tsdb directory having +# files not managed by the package. +[ + '/var/lib/prometheus/tsdb', +].each do |dir| + describe file(dir) do + it { should exist } + end +end + +[ + '/etc/prometheus/prometheus.yml', + '/etc/prometheus/web.yml', + '/etc/prometheus/rules.yml', + '/var/lib/prometheus/consoles/node-overview.html', + '/var/lib/prometheus/consoles/node-disk.html', + '/var/lib/prometheus/consoles/node-cpu.html', + '/var/lib/prometheus/consoles/node.html', + '/var/lib/prometheus/consoles/prometheus.html', + '/var/lib/prometheus/consoles/index.html.example', + '/var/lib/prometheus/consoles/prometheus-overview.html', + '/var/lib/prometheus/console_libraries/menu.lib', + '/var/lib/prometheus/console_libraries/prom.lib' +].each do |config| + describe file(config) do + it { should_not exist } + end +end + +describe file('/usr/share/doc/prometheus') do + it { should_not exist } +end + +[ + '/usr/share/doc/prometheus/NOTICE', + '/usr/share/doc/prometheus/LICENSE' +].each do |file| + describe file(file) do + it { should_not exist } + end +end + +# We do not cleanup the user, so it should still exist. +describe user('prometheus') do + it { should exist } + its('group') { should eq 'prometheus' } + its('lastlogin') { should eq nil } + its('shell') { should eq '/sbin/nologin' } +end + +describe group('prometheus') do + it { should exist } +end + +describe systemd_service('prometheus') do + it { should_not be_installed } +end + +describe port(9090) do + it { should_not be_listening } +end + +describe processes('prometheus') do + it { should_not exist } +end