mirror of
https://github.com/prometheus/node_exporter.git
synced 2025-01-20 23:39:02 +01:00
Merge branch 'master' into network_route
This commit is contained in:
commit
8536df5bbb
@ -8,7 +8,7 @@ repository:
|
|||||||
build:
|
build:
|
||||||
binaries:
|
binaries:
|
||||||
- name: node_exporter
|
- name: node_exporter
|
||||||
flags: -a -tags 'netgo static_build'
|
flags: -a -tags 'netgo osusergo static_build'
|
||||||
ldflags: |
|
ldflags: |
|
||||||
-X github.com/prometheus/common/version.Version={{.Version}}
|
-X github.com/prometheus/common/version.Version={{.Version}}
|
||||||
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
||||||
|
@ -7,7 +7,7 @@ repository:
|
|||||||
build:
|
build:
|
||||||
binaries:
|
binaries:
|
||||||
- name: node_exporter
|
- name: node_exporter
|
||||||
flags: -a -tags 'netgo static_build'
|
flags: -a -tags 'netgo osusergo static_build'
|
||||||
ldflags: |
|
ldflags: |
|
||||||
-X github.com/prometheus/common/version.Version={{.Version}}
|
-X github.com/prometheus/common/version.Version={{.Version}}
|
||||||
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
||||||
@ -31,3 +31,4 @@ crossbuild:
|
|||||||
- linux/ppc64
|
- linux/ppc64
|
||||||
- linux/ppc64le
|
- linux/ppc64le
|
||||||
- linux/s390x
|
- linux/s390x
|
||||||
|
- openbsd/amd64
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
* [FEATURE]
|
* [FEATURE]
|
||||||
* [ENHANCEMENT] Include TCP OutRsts in netstat metrics
|
* [ENHANCEMENT] Include TCP OutRsts in netstat metrics
|
||||||
* [ENHANCEMENT] Added XFS inode operations to XFS metrics
|
* [ENHANCEMENT] Added XFS inode operations to XFS metrics
|
||||||
|
* [ENHANCEMENT] Remove CGO dependencies for OpenBSD amd64
|
||||||
|
* [BUGFIX] Handle EPERM for syscall in timex collector
|
||||||
* [BUGFIX]
|
* [BUGFIX]
|
||||||
|
|
||||||
## 1.0.1 / 2020-06-15
|
## 1.0.1 / 2020-06-15
|
||||||
|
9
Makefile
9
Makefile
@ -44,9 +44,18 @@ else
|
|||||||
else
|
else
|
||||||
PROMU_CONF ?= .promu-cgo.yml
|
PROMU_CONF ?= .promu-cgo.yml
|
||||||
endif
|
endif
|
||||||
|
else
|
||||||
|
# Do not use CGO for openbsd/amd64 builds
|
||||||
|
ifeq ($(GOOS), openbsd)
|
||||||
|
ifeq ($(GOARCH), amd64)
|
||||||
|
PROMU_CONF ?= .promu.yml
|
||||||
else
|
else
|
||||||
PROMU_CONF ?= .promu-cgo.yml
|
PROMU_CONF ?= .promu-cgo.yml
|
||||||
endif
|
endif
|
||||||
|
else
|
||||||
|
PROMU_CONF ?= .promu-cgo.yml
|
||||||
|
endif
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
PROMU := $(FIRST_GOPATH)/bin/promu --config $(PROMU_CONF)
|
PROMU := $(FIRST_GOPATH)/bin/promu --config $(PROMU_CONF)
|
||||||
|
96
README.md
96
README.md
@ -14,6 +14,64 @@ To expose NVIDIA GPU metrics, [prometheus-dcgm
|
|||||||
](https://github.com/NVIDIA/gpu-monitoring-tools#dcgm-exporter)
|
](https://github.com/NVIDIA/gpu-monitoring-tools#dcgm-exporter)
|
||||||
can be used.
|
can be used.
|
||||||
|
|
||||||
|
## Installation and Usage
|
||||||
|
|
||||||
|
If you are new to Prometheus and `node_exporter` there is a [simple step-by-step guide](https://prometheus.io/docs/guides/node-exporter/).
|
||||||
|
|
||||||
|
### Ansible
|
||||||
|
|
||||||
|
For automated installs with [Ansible](https://www.ansible.com/), there is the [Cloud Alchemy role](https://github.com/cloudalchemy/ansible-node-exporter).
|
||||||
|
|
||||||
|
### RHEL/CentOS/Fedora
|
||||||
|
|
||||||
|
There is a [community-supplied COPR repository](https://copr.fedorainfracloud.org/coprs/ibotty/prometheus-exporters/) which closely follows upstream releases.
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
The `node_exporter` is designed to monitor the host system. It's not recommended
|
||||||
|
to deploy it as a Docker container because it requires access to the host system.
|
||||||
|
|
||||||
|
For situations where Docker deployment is needed, some extra flags must be used to allow
|
||||||
|
the `node_exporter` access to the host namespaces.
|
||||||
|
|
||||||
|
Be aware that any non-root mount points you want to monitor will need to be bind-mounted
|
||||||
|
into the container.
|
||||||
|
|
||||||
|
If you start container for host monitoring, specify `path.rootfs` argument.
|
||||||
|
This argument must match path in bind-mount of host root. The node\_exporter will use
|
||||||
|
`path.rootfs` as prefix to access host filesystem.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--net="host" \
|
||||||
|
--pid="host" \
|
||||||
|
-v "/:/host:ro,rslave" \
|
||||||
|
quay.io/prometheus/node-exporter:latest \
|
||||||
|
--path.rootfs=/host
|
||||||
|
```
|
||||||
|
|
||||||
|
For Docker compose, similar flag changes are needed.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
node_exporter:
|
||||||
|
image: quay.io/prometheus/node-exporter:latest
|
||||||
|
container_name: node_exporter
|
||||||
|
command:
|
||||||
|
- '--path.rootfs=/host'
|
||||||
|
network_mode: host
|
||||||
|
pid: host
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- '/:/host:ro,rslave'
|
||||||
|
```
|
||||||
|
|
||||||
|
On some systems, the `timex` collector requires an additional Docker flag,
|
||||||
|
`--cap-add=SYS_TIME`, in order to access the required syscalls.
|
||||||
|
|
||||||
## Collectors
|
## Collectors
|
||||||
|
|
||||||
There is varying support for collectors on each operating system. The tables
|
There is varying support for collectors on each operating system. The tables
|
||||||
@ -29,9 +87,10 @@ Name | Description | OS
|
|||||||
arp | Exposes ARP statistics from `/proc/net/arp`. | Linux
|
arp | Exposes ARP statistics from `/proc/net/arp`. | Linux
|
||||||
bcache | Exposes bcache statistics from `/sys/fs/bcache/`. | Linux
|
bcache | Exposes bcache statistics from `/sys/fs/bcache/`. | Linux
|
||||||
bonding | Exposes the number of configured and active slaves of Linux bonding interfaces. | Linux
|
bonding | Exposes the number of configured and active slaves of Linux bonding interfaces. | Linux
|
||||||
|
btrfs | Exposes btrfs statistics | Linux
|
||||||
boottime | Exposes system boot time derived from the `kern.boottime` sysctl. | Darwin, Dragonfly, FreeBSD, NetBSD, OpenBSD, Solaris
|
boottime | Exposes system boot time derived from the `kern.boottime` sysctl. | Darwin, Dragonfly, FreeBSD, NetBSD, OpenBSD, Solaris
|
||||||
conntrack | Shows conntrack statistics (does nothing if no `/proc/sys/net/netfilter/` present). | Linux
|
conntrack | Shows conntrack statistics (does nothing if no `/proc/sys/net/netfilter/` present). | Linux
|
||||||
cpu | Exposes CPU statistics | Darwin, Dragonfly, FreeBSD, Linux, Solaris
|
cpu | Exposes CPU statistics | Darwin, Dragonfly, FreeBSD, Linux, Solaris, OpenBSD
|
||||||
cpufreq | Exposes CPU frequency statistics | Linux, Solaris
|
cpufreq | Exposes CPU frequency statistics | Linux, Solaris
|
||||||
diskstats | Exposes disk I/O statistics. | Darwin, Linux, OpenBSD
|
diskstats | Exposes disk I/O statistics. | Darwin, Linux, OpenBSD
|
||||||
edac | Exposes error detection and correction statistics. | Linux
|
edac | Exposes error detection and correction statistics. | Linux
|
||||||
@ -50,6 +109,7 @@ netdev | Exposes network interface statistics such as bytes transferred. | Darwi
|
|||||||
netstat | Exposes network statistics from `/proc/net/netstat`. This is the same information as `netstat -s`. | Linux
|
netstat | Exposes network statistics from `/proc/net/netstat`. This is the same information as `netstat -s`. | Linux
|
||||||
nfs | Exposes NFS client statistics from `/proc/net/rpc/nfs`. This is the same information as `nfsstat -c`. | Linux
|
nfs | Exposes NFS client statistics from `/proc/net/rpc/nfs`. This is the same information as `nfsstat -c`. | Linux
|
||||||
nfsd | Exposes NFS kernel server statistics from `/proc/net/rpc/nfsd`. This is the same information as `nfsstat -s`. | Linux
|
nfsd | Exposes NFS kernel server statistics from `/proc/net/rpc/nfsd`. This is the same information as `nfsstat -s`. | Linux
|
||||||
|
powersupplyclass | Exposes Power Supply statistics from `/sys/class/power_supply` | Linux
|
||||||
pressure | Exposes pressure stall statistics from `/proc/pressure/`. | Linux (kernel 4.20+ and/or [CONFIG\_PSI](https://www.kernel.org/doc/html/latest/accounting/psi.html))
|
pressure | Exposes pressure stall statistics from `/proc/pressure/`. | Linux (kernel 4.20+ and/or [CONFIG\_PSI](https://www.kernel.org/doc/html/latest/accounting/psi.html))
|
||||||
rapl | Exposes various statistics from `/sys/class/powercap`. | Linux
|
rapl | Exposes various statistics from `/sys/class/powercap`. | Linux
|
||||||
schedstat | Exposes task scheduler statistics from `/proc/schedstat`. | Linux
|
schedstat | Exposes task scheduler statistics from `/proc/schedstat`. | Linux
|
||||||
@ -181,7 +241,7 @@ For advanced use the `node_exporter` can be passed an optional list of collector
|
|||||||
|
|
||||||
This can be useful for having different Prometheus servers collect specific metrics from nodes.
|
This can be useful for having different Prometheus servers collect specific metrics from nodes.
|
||||||
|
|
||||||
## Building and running
|
## Development building and running
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
|
|
||||||
@ -190,8 +250,8 @@ Prerequisites:
|
|||||||
|
|
||||||
Building:
|
Building:
|
||||||
|
|
||||||
go get github.com/prometheus/node_exporter
|
git clone https://github.com/prometheus/node_exporter.git
|
||||||
cd ${GOPATH-$HOME/go}/src/github.com/prometheus/node_exporter
|
cd node_exporter
|
||||||
make
|
make
|
||||||
./node_exporter <flags>
|
./node_exporter <flags>
|
||||||
|
|
||||||
@ -213,33 +273,7 @@ The exporter supports TLS via a new web configuration file.
|
|||||||
./node_exporter --web.config=web-config.yml
|
./node_exporter --web.config=web-config.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [https package](https/README.md) for more details.
|
See the [exporter-toolkit https package](https://github.com/prometheus/exporter-toolkit/blob/v0.1.0/https/README.md) for more details.
|
||||||
|
|
||||||
## Using Docker
|
|
||||||
The `node_exporter` is designed to monitor the host system. It's not recommended
|
|
||||||
to deploy it as a Docker container because it requires access to the host system.
|
|
||||||
Be aware that any non-root mount points you want to monitor will need to be bind-mounted
|
|
||||||
into the container.
|
|
||||||
|
|
||||||
If you start container for host monitoring, specify `path.rootfs` argument.
|
|
||||||
This argument must match path in bind-mount of host root. The node\_exporter will use
|
|
||||||
`path.rootfs` as prefix to access host filesystem.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d \
|
|
||||||
--net="host" \
|
|
||||||
--pid="host" \
|
|
||||||
-v "/:/host:ro,rslave" \
|
|
||||||
quay.io/prometheus/node-exporter \
|
|
||||||
--path.rootfs=/host
|
|
||||||
```
|
|
||||||
|
|
||||||
On some systems, the `timex` collector requires an additional Docker flag,
|
|
||||||
`--cap-add=SYS_TIME`, in order to access the required syscalls.
|
|
||||||
|
|
||||||
## Using a third-party repository for RHEL/CentOS/Fedora
|
|
||||||
|
|
||||||
There is a [community-supplied COPR repository](https://copr.fedorainfracloud.org/coprs/ibotty/prometheus-exporters/) which closely follows upstream releases.
|
|
||||||
|
|
||||||
[travis]: https://travis-ci.org/prometheus/node_exporter
|
[travis]: https://travis-ci.org/prometheus/node_exporter
|
||||||
[hub]: https://hub.docker.com/r/prom/node-exporter/
|
[hub]: https://hub.docker.com/r/prom/node-exporter/
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build freebsd dragonfly openbsd netbsd darwin
|
// +build freebsd dragonfly openbsd,!amd64 netbsd darwin
|
||||||
// +build !noboottime
|
// +build !noboottime
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
61
collector/boot_time_openbsd_amd64.go
Normal file
61
collector/boot_time_openbsd_amd64.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !noboottime
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-kit/kit/log"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bootTimeCollector struct {
|
||||||
|
name, description string
|
||||||
|
logger log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registerCollector("boottime", defaultEnabled, newBootTimeCollector)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBootTimeCollector returns a new Collector exposing system boot time on BSD systems.
|
||||||
|
func newBootTimeCollector(logger log.Logger) (Collector, error) {
|
||||||
|
return &bootTimeCollector{
|
||||||
|
name: "boot_time_seconds",
|
||||||
|
description: "Unix time of last boot, including microseconds.",
|
||||||
|
logger: logger,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update pushes boot time onto ch
|
||||||
|
func (c *bootTimeCollector) Update(ch chan<- prometheus.Metric) error {
|
||||||
|
raw, err := unix.SysctlRaw("kern.boottime")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tv := *(*unix.Timeval)(unsafe.Pointer(&raw[0]))
|
||||||
|
v := (float64(tv.Sec) + (float64(tv.Usec) / float64(1000*1000)))
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "", c.name),
|
||||||
|
c.description,
|
||||||
|
nil, nil,
|
||||||
|
), prometheus.GaugeValue, v)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build openbsd,!amd64
|
||||||
// +build !nocpu
|
// +build !nocpu
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
95
collector/cpu_openbsd_amd64.go
Normal file
95
collector/cpu_openbsd_amd64.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !nocpu
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/go-kit/kit/log"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
type clockinfo struct {
|
||||||
|
hz int32
|
||||||
|
tick int32
|
||||||
|
tickadj int32
|
||||||
|
stathz int32
|
||||||
|
profhz int32
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
CP_USER = iota
|
||||||
|
CP_NICE
|
||||||
|
CP_SYS
|
||||||
|
CP_SPIN
|
||||||
|
CP_INTR
|
||||||
|
CP_IDLE
|
||||||
|
CPUSTATES
|
||||||
|
)
|
||||||
|
|
||||||
|
type cpuCollector struct {
|
||||||
|
cpu typedDesc
|
||||||
|
logger log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registerCollector("cpu", defaultEnabled, NewCPUCollector)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCPUCollector(logger log.Logger) (Collector, error) {
|
||||||
|
return &cpuCollector{
|
||||||
|
cpu: typedDesc{nodeCPUSecondsDesc, prometheus.CounterValue},
|
||||||
|
logger: logger,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cpuCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
|
clockb, err := unix.SysctlRaw("kern.clockrate")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
clock := *(*clockinfo)(unsafe.Pointer(&clockb[0]))
|
||||||
|
hz := float64(clock.stathz)
|
||||||
|
|
||||||
|
ncpus, err := unix.SysctlUint32("hw.ncpu")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cpTime [][CPUSTATES]int64
|
||||||
|
for i := 0; i < int(ncpus); i++ {
|
||||||
|
cpb, err := unix.SysctlRaw("kern.cp_time2", i)
|
||||||
|
if err != nil && err != unix.ENODEV {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != unix.ENODEV {
|
||||||
|
cpTime = append(cpTime, *(*[CPUSTATES]int64)(unsafe.Pointer(&cpb[0])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for cpu, time := range cpTime {
|
||||||
|
lcpu := strconv.Itoa(cpu)
|
||||||
|
ch <- c.cpu.mustNewConstMetric(float64(time[CP_USER])/hz, lcpu, "user")
|
||||||
|
ch <- c.cpu.mustNewConstMetric(float64(time[CP_NICE])/hz, lcpu, "nice")
|
||||||
|
ch <- c.cpu.mustNewConstMetric(float64(time[CP_SYS])/hz, lcpu, "system")
|
||||||
|
ch <- c.cpu.mustNewConstMetric(float64(time[CP_SPIN])/hz, lcpu, "spin")
|
||||||
|
ch <- c.cpu.mustNewConstMetric(float64(time[CP_INTR])/hz, lcpu, "interrupt")
|
||||||
|
ch <- c.cpu.mustNewConstMetric(float64(time[CP_IDLE])/hz, lcpu, "idle")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build openbsd,!amd64
|
||||||
// +build !nodiskstats
|
// +build !nodiskstats
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
89
collector/diskstats_openbsd_amd64.go
Normal file
89
collector/diskstats_openbsd_amd64.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !nodiskstats
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/go-kit/kit/log"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DS_DISKNAMELEN = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
type DiskStats struct {
|
||||||
|
Name [DS_DISKNAMELEN]int8
|
||||||
|
Busy int32
|
||||||
|
Rxfer uint64
|
||||||
|
Wxfer uint64
|
||||||
|
Seek uint64
|
||||||
|
Rbytes uint64
|
||||||
|
Wbytes uint64
|
||||||
|
Attachtime unix.Timeval
|
||||||
|
Timestamp unix.Timeval
|
||||||
|
Time unix.Timeval
|
||||||
|
}
|
||||||
|
|
||||||
|
type diskstatsCollector struct {
|
||||||
|
rxfer typedDesc
|
||||||
|
rbytes typedDesc
|
||||||
|
wxfer typedDesc
|
||||||
|
wbytes typedDesc
|
||||||
|
time typedDesc
|
||||||
|
logger log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registerCollector("diskstats", defaultEnabled, NewDiskstatsCollector)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiskstatsCollector returns a new Collector exposing disk device stats.
|
||||||
|
func NewDiskstatsCollector(logger log.Logger) (Collector, error) {
|
||||||
|
return &diskstatsCollector{
|
||||||
|
rxfer: typedDesc{readsCompletedDesc, prometheus.CounterValue},
|
||||||
|
rbytes: typedDesc{readBytesDesc, prometheus.CounterValue},
|
||||||
|
wxfer: typedDesc{writesCompletedDesc, prometheus.CounterValue},
|
||||||
|
wbytes: typedDesc{writtenBytesDesc, prometheus.CounterValue},
|
||||||
|
time: typedDesc{ioTimeSecondsDesc, prometheus.CounterValue},
|
||||||
|
logger: logger,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||||
|
diskstatsb, err := unix.SysctlRaw("hw.diskstats")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ndisks := len(diskstatsb) / int(unsafe.Sizeof(DiskStats{}))
|
||||||
|
diskstats := *(*[]DiskStats)(unsafe.Pointer(&diskstatsb))
|
||||||
|
|
||||||
|
for i := 0; i < ndisks; i++ {
|
||||||
|
dn := *(*[DS_DISKNAMELEN]int8)(unsafe.Pointer(&diskstats[i].Name[0]))
|
||||||
|
diskname := int8ToString(dn[:])
|
||||||
|
|
||||||
|
ch <- c.rxfer.mustNewConstMetric(float64(diskstats[i].Rxfer), diskname)
|
||||||
|
ch <- c.rbytes.mustNewConstMetric(float64(diskstats[i].Rbytes), diskname)
|
||||||
|
ch <- c.wxfer.mustNewConstMetric(float64(diskstats[i].Wxfer), diskname)
|
||||||
|
ch <- c.wbytes.mustNewConstMetric(float64(diskstats[i].Wbytes), diskname)
|
||||||
|
time := float64(diskstats[i].Time.Sec) + float64(diskstats[i].Time.Usec)/1000000
|
||||||
|
ch <- c.time.mustNewConstMetric(time, diskname)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build openbsd darwin,amd64 dragonfly
|
// +build openbsd,!amd64 darwin,amd64 dragonfly
|
||||||
// +build !nofilesystem
|
// +build !nofilesystem
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
@ -73,7 +73,7 @@ func NewFilesystemCollector(logger log.Logger) (Collector, error) {
|
|||||||
subsystem := "filesystem"
|
subsystem := "filesystem"
|
||||||
level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.ignored-mount-points", "flag", *ignoredMountPoints)
|
level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.ignored-mount-points", "flag", *ignoredMountPoints)
|
||||||
mountPointPattern := regexp.MustCompile(*ignoredMountPoints)
|
mountPointPattern := regexp.MustCompile(*ignoredMountPoints)
|
||||||
level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.ignored-fs-types", "flag", *ignoredMountPoints)
|
level.Info(logger).Log("msg", "Parsed flag --collector.filesystem.ignored-fs-types", "flag", *ignoredFSTypes)
|
||||||
filesystemsTypesPattern := regexp.MustCompile(*ignoredFSTypes)
|
filesystemsTypesPattern := regexp.MustCompile(*ignoredFSTypes)
|
||||||
|
|
||||||
sizeDesc := prometheus.NewDesc(
|
sizeDesc := prometheus.NewDesc(
|
||||||
|
77
collector/filesystem_openbsd_amd64.go
Normal file
77
collector/filesystem_openbsd_amd64.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build openbsd darwin,amd64 dragonfly
|
||||||
|
// +build !nofilesystem
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-kit/kit/log/level"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defIgnoredMountPoints = "^/(dev)($|/)"
|
||||||
|
defIgnoredFSTypes = "^devfs$"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Expose filesystem fullness.
|
||||||
|
func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
|
||||||
|
var mnt []unix.Statfs_t
|
||||||
|
size, err := unix.Getfsstat(mnt, unix.MNT_NOWAIT)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mnt = make([]unix.Statfs_t, size)
|
||||||
|
_, err = unix.Getfsstat(mnt, unix.MNT_NOWAIT)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stats = []filesystemStats{}
|
||||||
|
for _, v := range mnt {
|
||||||
|
mountpoint := int8ToString(v.F_mntonname[:])
|
||||||
|
if c.ignoredMountPointsPattern.MatchString(mountpoint) {
|
||||||
|
level.Debug(c.logger).Log("msg", "Ignoring mount point", "mountpoint", mountpoint)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
device := int8ToString(v.F_mntfromname[:])
|
||||||
|
fstype := int8ToString(v.F_fstypename[:])
|
||||||
|
if c.ignoredFSTypesPattern.MatchString(fstype) {
|
||||||
|
level.Debug(c.logger).Log("msg", "Ignoring fs type", "type", fstype)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var ro float64
|
||||||
|
if (v.F_flags & unix.MNT_RDONLY) != 0 {
|
||||||
|
ro = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
stats = append(stats, filesystemStats{
|
||||||
|
labels: filesystemLabels{
|
||||||
|
device: device,
|
||||||
|
mountPoint: mountpoint,
|
||||||
|
fsType: fstype,
|
||||||
|
},
|
||||||
|
size: float64(v.F_blocks) * float64(v.F_bsize),
|
||||||
|
free: float64(v.F_bfree) * float64(v.F_bsize),
|
||||||
|
avail: float64(v.F_bavail) * float64(v.F_bsize),
|
||||||
|
files: float64(v.F_files),
|
||||||
|
filesFree: float64(v.F_ffree),
|
||||||
|
ro: ro,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return stats, nil
|
||||||
|
}
|
@ -3827,6 +3827,20 @@ node_zfs_zpool_rtime{zpool="poolz1"} 9.82909164e+09
|
|||||||
# TYPE node_zfs_zpool_rupdate untyped
|
# TYPE node_zfs_zpool_rupdate untyped
|
||||||
node_zfs_zpool_rupdate{zpool="pool1"} 7.921048984922e+13
|
node_zfs_zpool_rupdate{zpool="pool1"} 7.921048984922e+13
|
||||||
node_zfs_zpool_rupdate{zpool="poolz1"} 1.10734831944501e+14
|
node_zfs_zpool_rupdate{zpool="poolz1"} 1.10734831944501e+14
|
||||||
|
# HELP node_zfs_zpool_state kstat.zfs.misc.state
|
||||||
|
# TYPE node_zfs_zpool_state gauge
|
||||||
|
node_zfs_zpool_state{state="degraded",zpool="pool1"} 0
|
||||||
|
node_zfs_zpool_state{state="degraded",zpool="poolz1"} 1
|
||||||
|
node_zfs_zpool_state{state="faulted",zpool="pool1"} 0
|
||||||
|
node_zfs_zpool_state{state="faulted",zpool="poolz1"} 0
|
||||||
|
node_zfs_zpool_state{state="offline",zpool="pool1"} 0
|
||||||
|
node_zfs_zpool_state{state="offline",zpool="poolz1"} 0
|
||||||
|
node_zfs_zpool_state{state="online",zpool="pool1"} 1
|
||||||
|
node_zfs_zpool_state{state="online",zpool="poolz1"} 0
|
||||||
|
node_zfs_zpool_state{state="removed",zpool="pool1"} 0
|
||||||
|
node_zfs_zpool_state{state="removed",zpool="poolz1"} 0
|
||||||
|
node_zfs_zpool_state{state="unavail",zpool="pool1"} 0
|
||||||
|
node_zfs_zpool_state{state="unavail",zpool="poolz1"} 0
|
||||||
# HELP node_zfs_zpool_wcnt kstat.zfs.misc.io.wcnt
|
# HELP node_zfs_zpool_wcnt kstat.zfs.misc.io.wcnt
|
||||||
# TYPE node_zfs_zpool_wcnt untyped
|
# TYPE node_zfs_zpool_wcnt untyped
|
||||||
node_zfs_zpool_wcnt{zpool="pool1"} 0
|
node_zfs_zpool_wcnt{zpool="pool1"} 0
|
||||||
|
1
collector/fixtures/proc/spl/kstat/zfs/pool1/state
Normal file
1
collector/fixtures/proc/spl/kstat/zfs/pool1/state
Normal file
@ -0,0 +1 @@
|
|||||||
|
ONLINE
|
1
collector/fixtures/proc/spl/kstat/zfs/poolz1/state
Normal file
1
collector/fixtures/proc/spl/kstat/zfs/poolz1/state
Normal file
@ -0,0 +1 @@
|
|||||||
|
DEGRADED
|
@ -79,6 +79,10 @@ func NewInfiniBandCollector(logger log.Logger) (Collector, error) {
|
|||||||
"state_id": "State of the InfiniBand port (0: no change, 1: down, 2: init, 3: armed, 4: active, 5: act defer)",
|
"state_id": "State of the InfiniBand port (0: no change, 1: down, 2: init, 3: armed, 4: active, 5: act defer)",
|
||||||
"unicast_packets_received_total": "Number of unicast packets received (including errors)",
|
"unicast_packets_received_total": "Number of unicast packets received (including errors)",
|
||||||
"unicast_packets_transmitted_total": "Number of unicast packets transmitted (including errors)",
|
"unicast_packets_transmitted_total": "Number of unicast packets transmitted (including errors)",
|
||||||
|
"port_receive_remote_physical_errors_total": "Number of packets marked with the EBP (End of Bad Packet) delimiter received on the port.",
|
||||||
|
"port_receive_switch_relay_errors_total": "Number of packets that could not be forwarded by the switch.",
|
||||||
|
"symbol_error_total": "Number of minor link errors detected on one or more physical lanes.",
|
||||||
|
"vl15_dropped_total": "Number of incoming VL15 packets dropped due to resource limitations.",
|
||||||
}
|
}
|
||||||
|
|
||||||
i.metricDescs = make(map[string]*prometheus.Desc)
|
i.metricDescs = make(map[string]*prometheus.Desc)
|
||||||
@ -157,6 +161,10 @@ func (c *infinibandCollector) Update(ch chan<- prometheus.Metric) error {
|
|||||||
c.pushCounter(ch, "port_transmit_wait_total", port.Counters.PortXmitWait, port.Name, portStr)
|
c.pushCounter(ch, "port_transmit_wait_total", port.Counters.PortXmitWait, port.Name, portStr)
|
||||||
c.pushCounter(ch, "unicast_packets_received_total", port.Counters.UnicastRcvPackets, port.Name, portStr)
|
c.pushCounter(ch, "unicast_packets_received_total", port.Counters.UnicastRcvPackets, port.Name, portStr)
|
||||||
c.pushCounter(ch, "unicast_packets_transmitted_total", port.Counters.UnicastXmitPackets, port.Name, portStr)
|
c.pushCounter(ch, "unicast_packets_transmitted_total", port.Counters.UnicastXmitPackets, port.Name, portStr)
|
||||||
|
c.pushCounter(ch, "port_receive_remote_physical_errors_total", port.Counters.PortRcvRemotePhysicalErrors, port.Name, portStr)
|
||||||
|
c.pushCounter(ch, "port_receive_switch_relay_errors_total", port.Counters.PortRcvSwitchRelayErrors, port.Name, portStr)
|
||||||
|
c.pushCounter(ch, "symbol_error_total", port.Counters.SymbolError, port.Name, portStr)
|
||||||
|
c.pushCounter(ch, "vl15_dropped_total", port.Counters.VL15Dropped, port.Name, portStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build openbsd,!amd64
|
||||||
// +build !nointerrupts
|
// +build !nointerrupts
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
109
collector/interrupts_openbsd_amd64.go
Normal file
109
collector/interrupts_openbsd_amd64.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !nointerrupts
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
KERN_INTRCNT = 63
|
||||||
|
KERN_INTRCNT_NUM = 1
|
||||||
|
KERN_INTRCNT_CNT = 2
|
||||||
|
KERN_INTRCNT_NAME = 3
|
||||||
|
KERN_INTRCNT_VECTOR = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
func nintr() _C_int {
|
||||||
|
mib := [3]_C_int{unix.CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NUM}
|
||||||
|
buf, err := sysctl(mib[:])
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return *(*_C_int)(unsafe.Pointer(&buf[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func intr(idx _C_int) (itr interrupt, err error) {
|
||||||
|
mib := [4]_C_int{unix.CTL_KERN, KERN_INTRCNT, KERN_INTRCNT_NAME, idx}
|
||||||
|
buf, err := sysctl(mib[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dev := *(*[128]byte)(unsafe.Pointer(&buf[0]))
|
||||||
|
itr.device = string(dev[:])
|
||||||
|
|
||||||
|
mib[2] = KERN_INTRCNT_VECTOR
|
||||||
|
buf, err = sysctl(mib[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
itr.vector = *(*int)(unsafe.Pointer(&buf[0]))
|
||||||
|
|
||||||
|
mib[2] = KERN_INTRCNT_CNT
|
||||||
|
buf, err = sysctl(mib[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count := *(*uint64)(unsafe.Pointer(&buf[0]))
|
||||||
|
itr.values = []float64{float64(count)}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var interruptLabelNames = []string{"cpu", "type", "devices"}
|
||||||
|
|
||||||
|
func (c *interruptsCollector) Update(ch chan<- prometheus.Metric) error {
|
||||||
|
interrupts, err := getInterrupts()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("couldn't get interrupts: %s", err)
|
||||||
|
}
|
||||||
|
for dev, interrupt := range interrupts {
|
||||||
|
for cpuNo, value := range interrupt.values {
|
||||||
|
ch <- c.desc.mustNewConstMetric(
|
||||||
|
value,
|
||||||
|
strconv.Itoa(cpuNo),
|
||||||
|
fmt.Sprintf("%d", interrupt.vector),
|
||||||
|
dev,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type interrupt struct {
|
||||||
|
vector int
|
||||||
|
device string
|
||||||
|
values []float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInterrupts() (map[string]interrupt, error) {
|
||||||
|
var interrupts = map[string]interrupt{}
|
||||||
|
n := nintr()
|
||||||
|
|
||||||
|
for i := _C_int(0); i < n; i++ {
|
||||||
|
itr, err := intr(i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
interrupts[itr.device] = itr
|
||||||
|
}
|
||||||
|
|
||||||
|
return interrupts, nil
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// +build openbsd
|
// +build openbsd,!amd64
|
||||||
// +build !nomeminfo
|
// +build !nomeminfo
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
44
collector/meminfo_openbsd_amd64.go
Normal file
44
collector/meminfo_openbsd_amd64.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License")
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !nomeminfo
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
|
||||||
|
uvmexpb, err := unix.SysctlRaw("vm.uvmexp")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
uvmexp := *(*unix.Uvmexp)(unsafe.Pointer(&uvmexpb[0]))
|
||||||
|
ps := float64(uvmexp.Pagesize)
|
||||||
|
|
||||||
|
// see uvm(9)
|
||||||
|
return map[string]float64{
|
||||||
|
"active_bytes": ps * float64(uvmexp.Active),
|
||||||
|
"cache_bytes": ps * float64(uvmexp.Vnodepages),
|
||||||
|
"free_bytes": ps * float64(uvmexp.Free),
|
||||||
|
"inactive_bytes": ps * float64(uvmexp.Inactive),
|
||||||
|
"size_bytes": ps * float64(uvmexp.Npages),
|
||||||
|
"swap_size_bytes": ps * float64(uvmexp.Swpages),
|
||||||
|
"swap_used_bytes": ps * float64(uvmexp.Swpginuse),
|
||||||
|
"swapped_in_pages_bytes_total": ps * float64(uvmexp.Pgswapin),
|
||||||
|
"swapped_out_pages_bytes_total": ps * float64(uvmexp.Pgswapout),
|
||||||
|
"wired_bytes": ps * float64(uvmexp.Wired),
|
||||||
|
}, nil
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build openbsd,!amd64
|
||||||
// +build !nonetdev
|
// +build !nonetdev
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
78
collector/netdev_openbsd_amd64.go
Normal file
78
collector/netdev_openbsd_amd64.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build !nonetdev
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-kit/kit/log"
|
||||||
|
"github.com/go-kit/kit/log/level"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"regexp"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getNetDevStats(ignore *regexp.Regexp, accept *regexp.Regexp, logger log.Logger) (netDevStats, error) {
|
||||||
|
netDev := netDevStats{}
|
||||||
|
|
||||||
|
mib := [6]_C_int{unix.CTL_NET, unix.AF_ROUTE, 0, 0, unix.NET_RT_IFLIST, 0}
|
||||||
|
buf, err := sysctl(mib[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
n := uintptr(len(buf))
|
||||||
|
index := uintptr(unsafe.Pointer(&buf[0]))
|
||||||
|
next := uintptr(0)
|
||||||
|
|
||||||
|
var rtm *unix.RtMsghdr
|
||||||
|
|
||||||
|
for next = index; next < (index + n); next += uintptr(rtm.Msglen) {
|
||||||
|
rtm = (*unix.RtMsghdr)(unsafe.Pointer(next))
|
||||||
|
if rtm.Version != unix.RTM_VERSION || rtm.Type != unix.RTM_IFINFO {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ifm := (*unix.IfMsghdr)(unsafe.Pointer(next))
|
||||||
|
if ifm.Addrs&unix.RTA_IFP == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dl := (*unix.RawSockaddrDatalink)(unsafe.Pointer(next + uintptr(rtm.Hdrlen)))
|
||||||
|
if dl.Family != unix.AF_LINK {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data := ifm.Data
|
||||||
|
dev := int8ToString(dl.Data[:dl.Nlen])
|
||||||
|
if ignore != nil && ignore.MatchString(dev) {
|
||||||
|
level.Debug(logger).Log("msg", "Ignoring device", "device", dev)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if accept != nil && !accept.MatchString(dev) {
|
||||||
|
level.Debug(logger).Log("msg", "Ignoring device", "device", dev)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
netDev[dev] = map[string]uint64{
|
||||||
|
"receive_packets": data.Ipackets,
|
||||||
|
"transmit_packets": data.Opackets,
|
||||||
|
"receive_errs": data.Ierrors,
|
||||||
|
"transmit_errs": data.Oerrors,
|
||||||
|
"receive_bytes": data.Ibytes,
|
||||||
|
"transmit_bytes": data.Obytes,
|
||||||
|
"receive_multicast": data.Imcasts,
|
||||||
|
"transmit_multicast": data.Omcasts,
|
||||||
|
"receive_drop": data.Iqdrops,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return netDev, nil
|
||||||
|
}
|
86
collector/sysctl_openbsd_amd64.go
Normal file
86
collector/sysctl_openbsd_amd64.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2020 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func int8ToString(a []int8) string {
|
||||||
|
buf := make([]byte, len(a))
|
||||||
|
for i, v := range a {
|
||||||
|
if byte(v) == 0 {
|
||||||
|
buf = buf[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buf[i] = byte(v)
|
||||||
|
}
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unix._C_int
|
||||||
|
type _C_int int32
|
||||||
|
|
||||||
|
var _zero uintptr
|
||||||
|
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case unix.EAGAIN:
|
||||||
|
return syscall.EAGAIN
|
||||||
|
case unix.EINVAL:
|
||||||
|
return syscall.EINVAL
|
||||||
|
case unix.ENOENT:
|
||||||
|
return syscall.ENOENT
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func _sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
|
||||||
|
var _p0 unsafe.Pointer
|
||||||
|
if len(mib) > 0 {
|
||||||
|
_p0 = unsafe.Pointer(&mib[0])
|
||||||
|
} else {
|
||||||
|
_p0 = unsafe.Pointer(&_zero)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
_, _, e1 := unix.Syscall6(unix.SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
if err != unix.EINTR {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func sysctl(mib []_C_int) ([]byte, error) {
|
||||||
|
n := uintptr(0)
|
||||||
|
if err := _sysctl(mib, nil, &n, nil, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, n)
|
||||||
|
if err := _sysctl(mib, &buf[0], &n, nil, 0); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf[:n], nil
|
||||||
|
}
|
@ -17,9 +17,12 @@
|
|||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/go-kit/kit/log"
|
"github.com/go-kit/kit/log"
|
||||||
|
"github.com/go-kit/kit/log/level"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
@ -163,6 +166,10 @@ func (c *timexCollector) Update(ch chan<- prometheus.Metric) error {
|
|||||||
|
|
||||||
status, err := unix.Adjtimex(timex)
|
status, err := unix.Adjtimex(timex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, os.ErrPermission) {
|
||||||
|
level.Debug(c.logger).Log("msg", "Not collecting timex metrics", "err", err)
|
||||||
|
return ErrNoData
|
||||||
|
}
|
||||||
return fmt.Errorf("failed to retrieve adjtimex stats: %w", err)
|
return fmt.Errorf("failed to retrieve adjtimex stats: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ type zfsCollector struct {
|
|||||||
linuxProcpathBase string
|
linuxProcpathBase string
|
||||||
linuxZpoolIoPath string
|
linuxZpoolIoPath string
|
||||||
linuxZpoolObjsetPath string
|
linuxZpoolObjsetPath string
|
||||||
|
linuxZpoolStatePath string
|
||||||
linuxPathMap map[string]string
|
linuxPathMap map[string]string
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
}
|
}
|
||||||
@ -47,6 +48,7 @@ func NewZFSCollector(logger log.Logger) (Collector, error) {
|
|||||||
linuxProcpathBase: "spl/kstat/zfs",
|
linuxProcpathBase: "spl/kstat/zfs",
|
||||||
linuxZpoolIoPath: "/*/io",
|
linuxZpoolIoPath: "/*/io",
|
||||||
linuxZpoolObjsetPath: "/*/objset-*",
|
linuxZpoolObjsetPath: "/*/objset-*",
|
||||||
|
linuxZpoolStatePath: "/*/state",
|
||||||
linuxPathMap: map[string]string{
|
linuxPathMap: map[string]string{
|
||||||
"zfs_abd": "abdstats",
|
"zfs_abd": "abdstats",
|
||||||
"zfs_arc": "arcstats",
|
"zfs_arc": "arcstats",
|
||||||
@ -132,3 +134,18 @@ func (c *zfsCollector) constPoolObjsetMetric(poolName string, datasetName string
|
|||||||
datasetName,
|
datasetName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *zfsCollector) constPoolStateMetric(poolName string, stateName string, isActive uint64) prometheus.Metric {
|
||||||
|
return prometheus.MustNewConstMetric(
|
||||||
|
prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(namespace, "zfs_zpool", "state"),
|
||||||
|
"kstat.zfs.misc.state",
|
||||||
|
[]string{"zpool", "state"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(isActive),
|
||||||
|
poolName,
|
||||||
|
stateName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -41,6 +41,8 @@ const (
|
|||||||
// kstatDataString = "7"
|
// kstatDataString = "7"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var zfsPoolStatesName = []string{"online", "degraded", "faulted", "offline", "removed", "unavail"}
|
||||||
|
|
||||||
func (c *zfsCollector) openProcFile(path string) (*os.File, error) {
|
func (c *zfsCollector) openProcFile(path string) (*os.File, error) {
|
||||||
file, err := os.Open(procFilePath(path))
|
file, err := os.Open(procFilePath(path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -97,10 +99,6 @@ func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if zpoolObjsetPaths == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, zpoolPath := range zpoolObjsetPaths {
|
for _, zpoolPath := range zpoolObjsetPaths {
|
||||||
file, err := os.Open(zpoolPath)
|
file, err := os.Open(zpoolPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,6 +115,34 @@ func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zpoolStatePaths, err := filepath.Glob(procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolStatePath)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if zpoolStatePaths == nil {
|
||||||
|
level.Warn(c.logger).Log("msg", "Not found pool state files")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, zpoolPath := range zpoolStatePaths {
|
||||||
|
file, err := os.Open(zpoolPath)
|
||||||
|
if err != nil {
|
||||||
|
// this file should exist, but there is a race where an exporting pool can remove the files -- ok to ignore
|
||||||
|
level.Debug(c.logger).Log("msg", "Cannot open file for reading", "path", zpoolPath)
|
||||||
|
return errZFSNotAvailable
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.parsePoolStateFile(file, zpoolPath, func(poolName string, stateName string, isActive uint64) {
|
||||||
|
ch <- c.constPoolStateMetric(poolName, stateName, isActive)
|
||||||
|
})
|
||||||
|
|
||||||
|
file.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,3 +261,35 @@ func (c *zfsCollector) parsePoolObjsetFile(reader io.Reader, zpoolPath string, h
|
|||||||
|
|
||||||
return scanner.Err()
|
return scanner.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *zfsCollector) parsePoolStateFile(reader io.Reader, zpoolPath string, handler func(string, string, uint64)) error {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
scanner.Scan()
|
||||||
|
|
||||||
|
actualStateName, err := scanner.Text(), scanner.Err()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
actualStateName = strings.ToLower(actualStateName)
|
||||||
|
|
||||||
|
zpoolPathElements := strings.Split(zpoolPath, "/")
|
||||||
|
pathLen := len(zpoolPathElements)
|
||||||
|
if pathLen < 2 {
|
||||||
|
return fmt.Errorf("zpool path did not return at least two elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
zpoolName := zpoolPathElements[pathLen-2]
|
||||||
|
|
||||||
|
for _, stateName := range zfsPoolStatesName {
|
||||||
|
isActive := uint64(0)
|
||||||
|
|
||||||
|
if actualStateName == stateName {
|
||||||
|
isActive = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
handler(zpoolName, stateName, isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -494,3 +494,52 @@ func TestVdevMirrorstatsParsing(t *testing.T) {
|
|||||||
t.Fatal("VdevMirrorStats parsing handler was not called for some expected sysctls")
|
t.Fatal("VdevMirrorStats parsing handler was not called for some expected sysctls")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPoolStateParsing(t *testing.T) {
|
||||||
|
zpoolPaths, err := filepath.Glob("fixtures/proc/spl/kstat/zfs/*/state")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := zfsCollector{}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerCalled := false
|
||||||
|
for _, zpoolPath := range zpoolPaths {
|
||||||
|
file, err := os.Open(zpoolPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.parsePoolStateFile(file, zpoolPath, func(poolName string, stateName string, isActive uint64) {
|
||||||
|
handlerCalled = true
|
||||||
|
|
||||||
|
if poolName == "pool1" {
|
||||||
|
if isActive != uint64(1) && stateName == "online" {
|
||||||
|
t.Fatalf("Incorrect parsed value for online state")
|
||||||
|
}
|
||||||
|
if isActive != uint64(0) && stateName != "online" {
|
||||||
|
t.Fatalf("Incorrect parsed value for online state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if poolName == "poolz1" {
|
||||||
|
if isActive != uint64(1) && stateName == "degraded" {
|
||||||
|
t.Fatalf("Incorrect parsed value for degraded state")
|
||||||
|
}
|
||||||
|
if isActive != uint64(0) && stateName != "degraded" {
|
||||||
|
t.Fatalf("Incorrect parsed value for degraded state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
file.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !handlerCalled {
|
||||||
|
t.Fatal("Zpool parsing handler was not called for some expected sysctls")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
6
go.mod
6
go.mod
@ -12,22 +12,20 @@ require (
|
|||||||
github.com/mattn/go-xmlrpc v0.0.3
|
github.com/mattn/go-xmlrpc v0.0.3
|
||||||
github.com/mdlayher/genetlink v1.0.0 // indirect
|
github.com/mdlayher/genetlink v1.0.0 // indirect
|
||||||
github.com/mdlayher/wifi v0.0.0-20200527114002-84f0b9457fdd
|
github.com/mdlayher/wifi v0.0.0-20200527114002-84f0b9457fdd
|
||||||
github.com/pkg/errors v0.9.1
|
|
||||||
github.com/prometheus/client_golang v1.7.1
|
github.com/prometheus/client_golang v1.7.1
|
||||||
github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model v0.2.0
|
||||||
github.com/prometheus/common v0.14.0
|
github.com/prometheus/common v0.15.0
|
||||||
|
github.com/prometheus/exporter-toolkit v0.5.0
|
||||||
github.com/prometheus/procfs v0.2.0
|
github.com/prometheus/procfs v0.2.0
|
||||||
github.com/siebenmann/go-kstat v0.0.0-20200303194639-4e8294f9e9d5
|
github.com/siebenmann/go-kstat v0.0.0-20200303194639-4e8294f9e9d5
|
||||||
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
|
github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a
|
||||||
go.uber.org/multierr v1.5.0 // indirect
|
go.uber.org/multierr v1.5.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
|
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a // indirect
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a // indirect
|
||||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435
|
golang.org/x/sys v0.0.0-20201202213521-69691e467435
|
||||||
golang.org/x/tools v0.0.0-20200513201620-d5fe73897c97 // indirect
|
golang.org/x/tools v0.0.0-20200513201620-d5fe73897c97 // indirect
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
|
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
22
go.sum
22
go.sum
@ -290,8 +290,10 @@ github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLy
|
|||||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||||
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
|
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
|
||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
|
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
|
||||||
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||||
|
github.com/prometheus/exporter-toolkit v0.5.0 h1:GwrxhCviqOl8Mm0vKqkh7Xy54m+FPlHEJacFs48M3gY=
|
||||||
|
github.com/prometheus/exporter-toolkit v0.5.0/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
|
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
|
||||||
@ -367,8 +369,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9 h1:sYNJzB4J8toYPQTM6pAkcmBRgw9SnQKP9oXCHfgy604=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
@ -446,6 +448,7 @@ golang.org/x/sys v0.0.0-20190902133755-9109b7679e13 h1:tdsQdquKbTNMsSZLqnLELJGzC
|
|||||||
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -453,12 +456,9 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860 h1:YEu4SMq7D0cmT7CBbXfcH0NZeuChAXwsHe/9XueUO6o=
|
||||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
|
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435 h1:25AvDqqB9PrNqj1FLf2/70I4W0L19qqoaFq3gjNwbKk=
|
|
||||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.3.0/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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
@ -537,6 +537,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
# HTTPS Package for Prometheus
|
|
||||||
|
|
||||||
The `https` directory contains a Go package and a sample configuration file for
|
|
||||||
running `node_exporter` with HTTPS instead of HTTP. We currently support TLS 1.3
|
|
||||||
and TLS 1.2.
|
|
||||||
|
|
||||||
To run a server with TLS, use the flag `--web.config`.
|
|
||||||
|
|
||||||
e.g. `./node_exporter --web.config="web-config.yml"`
|
|
||||||
If the config is kept within the https directory.
|
|
||||||
|
|
||||||
The config file should be written in YAML format, and is reloaded on each connection to check for new certificates and/or authentication policy.
|
|
||||||
|
|
||||||
## Sample Config
|
|
||||||
|
|
||||||
```
|
|
||||||
tls_server_config:
|
|
||||||
# Certificate and key files for server to use to authenticate to client.
|
|
||||||
cert_file: <filename>
|
|
||||||
key_file: <filename>
|
|
||||||
|
|
||||||
# Server policy for client authentication. Maps to ClientAuth Policies.
|
|
||||||
# For more detail on clientAuth options: [ClientAuthType](https://golang.org/pkg/crypto/tls/#ClientAuthType)
|
|
||||||
[ client_auth_type: <string> | default = "NoClientCert" ]
|
|
||||||
|
|
||||||
# CA certificate for client certificate authentication to the server.
|
|
||||||
[ client_ca_file: <filename> ]
|
|
||||||
|
|
||||||
# Minimum TLS version that is acceptable.
|
|
||||||
[ min_version: <string> | default = "TLS12" ]
|
|
||||||
|
|
||||||
# Maximum TLS version that is acceptable.
|
|
||||||
[ max_version: <string> | default = "TLS13" ]
|
|
||||||
|
|
||||||
# List of supported cipher suites for TLS versions up to TLS 1.2. If empty,
|
|
||||||
# Go default cipher suites are used. Available cipher suites are documented
|
|
||||||
# in the go documentation:
|
|
||||||
# https://golang.org/pkg/crypto/tls/#pkg-constants
|
|
||||||
[ cipher_suites:
|
|
||||||
[ - <string> ] ]
|
|
||||||
|
|
||||||
# prefer_server_cipher_suites controls whether the server selects the
|
|
||||||
# client's most preferred ciphersuite, or the server's most preferred
|
|
||||||
# ciphersuite. If true then the server's preference, as expressed in
|
|
||||||
# the order of elements in cipher_suites, is used.
|
|
||||||
[ prefer_server_cipher_suites: <bool> | default = true ]
|
|
||||||
|
|
||||||
# Elliptic curves that will be used in an ECDHE handshake, in preference
|
|
||||||
# order. Available curves are documented in the go documentation:
|
|
||||||
# https://golang.org/pkg/crypto/tls/#CurveID
|
|
||||||
[ curve_preferences:
|
|
||||||
[ - <string> ] ]
|
|
||||||
|
|
||||||
http_server_config:
|
|
||||||
# Enable HTTP/2 support. Note that HTTP/2 is only supported with TLS.
|
|
||||||
# This can not be changed on the fly.
|
|
||||||
[ http2: <bool> | default = true ]
|
|
||||||
|
|
||||||
# Usernames and hashed passwords that have full access to the web
|
|
||||||
# server via basic authentication. If empty, no basic authentication is
|
|
||||||
# required. Passwords are hashed with bcrypt.
|
|
||||||
basic_auth_users:
|
|
||||||
[ <string>: <secret> ... ]
|
|
||||||
```
|
|
||||||
|
|
||||||
## About bcrypt
|
|
||||||
|
|
||||||
There are several tools out there to generate bcrypt passwords, e.g.
|
|
||||||
[htpasswd](https://httpd.apache.org/docs/2.4/programs/htpasswd.html):
|
|
||||||
|
|
||||||
`htpasswd -nBC 10 "" | tr -d ':\n'`
|
|
||||||
|
|
||||||
That command will prompt you for a password and output the hashed password,
|
|
||||||
which will look something like:
|
|
||||||
`$2y$10$X0h1gDsPszWURQaxFh.zoubFi6DXncSjhoQNJgRrnGs7EsimhC7zG`
|
|
||||||
|
|
||||||
The cost (10 in the example) influences the time it takes for computing the
|
|
||||||
hash. A higher cost will en up slowing down the authentication process.
|
|
||||||
Depending on the machine, a cost of 10 will take about ~70ms where a cost of
|
|
||||||
18 can take up to a few seconds. That hash will be computed on every
|
|
||||||
password-protected request.
|
|
96
https/testdata/server.crt
vendored
96
https/testdata/server.crt
vendored
@ -1,96 +0,0 @@
|
|||||||
Certificate:
|
|
||||||
Data:
|
|
||||||
Version: 3 (0x2)
|
|
||||||
Serial Number: 1 (0x1)
|
|
||||||
Signature Algorithm: sha1WithRSAEncryption
|
|
||||||
Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus TLS CA
|
|
||||||
Validity
|
|
||||||
Not Before: Apr 5 08:06:57 2019 GMT
|
|
||||||
Not After : Mar 26 08:06:57 2059 GMT
|
|
||||||
Subject: C=US, O=Prometheus, CN=prometheus.example.com
|
|
||||||
Subject Public Key Info:
|
|
||||||
Public Key Algorithm: rsaEncryption
|
|
||||||
RSA Public-Key: (2048 bit)
|
|
||||||
Modulus:
|
|
||||||
00:bd:6c:b6:7f:d1:2f:be:e4:41:eb:5d:ff:50:78:
|
|
||||||
03:2b:76:03:da:01:48:20:13:90:66:c9:ce:6e:06:
|
|
||||||
e5:fa:2d:0d:c0:b0:46:28:44:10:a0:61:79:87:a2:
|
|
||||||
98:4c:29:fa:f9:bb:0f:44:c7:90:5c:5c:55:60:cd:
|
|
||||||
45:da:b8:e4:dd:28:72:c8:8b:a1:3e:4b:00:09:82:
|
|
||||||
b0:2c:dc:d6:17:c9:02:f4:cd:26:c7:11:28:f3:77:
|
|
||||||
b5:97:c2:76:c2:e0:07:d7:34:5b:e0:ed:1a:59:a5:
|
|
||||||
b4:b7:16:09:3d:35:bd:d9:03:07:9d:7c:3b:f0:63:
|
|
||||||
bd:5e:02:99:cf:32:e1:ac:4c:7a:3e:4c:b2:8e:98:
|
|
||||||
68:07:4f:59:dc:0d:bf:cc:83:04:5c:d8:90:f0:73:
|
|
||||||
da:2b:08:17:c4:36:a7:d8:94:3d:b6:c0:af:29:0a:
|
|
||||||
d3:19:5f:eb:7d:cc:4d:05:56:11:0a:ee:b1:f3:d7:
|
|
||||||
c9:5a:3c:8c:57:16:91:51:14:f8:20:4e:0f:29:9e:
|
|
||||||
04:21:e6:f1:e4:e8:44:af:d7:25:92:08:64:fc:2c:
|
|
||||||
1c:2e:4f:71:53:91:53:1d:e5:f9:7b:52:0f:21:da:
|
|
||||||
5c:dd:19:68:96:ca:70:6a:f1:c4:0d:07:af:f8:65:
|
|
||||||
13:92:e9:ef:65:b3:89:86:fd:c0:74:5c:a4:6b:49:
|
|
||||||
62:c5
|
|
||||||
Exponent: 65537 (0x10001)
|
|
||||||
X509v3 extensions:
|
|
||||||
X509v3 Key Usage: critical
|
|
||||||
Digital Signature, Key Encipherment
|
|
||||||
X509v3 Basic Constraints:
|
|
||||||
CA:FALSE
|
|
||||||
X509v3 Extended Key Usage:
|
|
||||||
TLS Web Server Authentication, TLS Web Client Authentication
|
|
||||||
X509v3 Subject Key Identifier:
|
|
||||||
00:61:01:AD:25:44:8A:EF:E1:2C:EC:83:5A:3A:3B:EA:A0:BD:E1:45
|
|
||||||
X509v3 Authority Key Identifier:
|
|
||||||
keyid:4D:02:BF:71:95:6A:AA:58:C5:9C:B8:83:67:5E:64:16:99:E1:2A:9E
|
|
||||||
|
|
||||||
Authority Information Access:
|
|
||||||
CA Issuers - URI:http://example.com/ca/tls-ca.cer
|
|
||||||
|
|
||||||
X509v3 CRL Distribution Points:
|
|
||||||
|
|
||||||
Full Name:
|
|
||||||
URI:http://example.com/ca/tls-ca.crl
|
|
||||||
|
|
||||||
X509v3 Subject Alternative Name:
|
|
||||||
IP Address:127.0.0.1, IP Address:127.0.0.0, DNS:localhost
|
|
||||||
Signature Algorithm: sha1WithRSAEncryption
|
|
||||||
77:97:e4:ef:db:10:8e:62:50:96:4a:6e:f5:a4:f9:1f:19:3b:
|
|
||||||
c8:a4:dd:b3:f6:11:41:1a:fb:e3:f8:dd:0e:64:e5:2b:00:b9:
|
|
||||||
e6:25:9f:2e:e1:d2:9a:cd:b6:f2:41:4d:27:dd:2c:9a:af:97:
|
|
||||||
79:e8:cf:61:fb:cf:be:25:c6:e1:19:a0:c8:90:44:a0:76:8a:
|
|
||||||
45:d4:37:22:e5:d4:80:b4:b3:0f:a8:33:08:24:ad:21:0b:b7:
|
|
||||||
98:46:93:90:8a:ae:77:0c:cb:b8:59:d3:3b:9b:fb:16:5a:22:
|
|
||||||
ca:c2:97:9d:78:1b:fc:23:fc:a0:42:54:40:de:88:4b:07:2b:
|
|
||||||
19:4e:0e:79:bf:c9:9f:01:a6:46:c5:55:fa:9f:c0:0d:8a:a6:
|
|
||||||
e1:47:16:a6:0e:be:23:c9:e9:58:d6:31:71:8c:80:9c:16:64:
|
|
||||||
f0:14:08:22:a1:23:7c:98:b9:62:d1:4a:ce:e3:5c:59:fb:41:
|
|
||||||
87:a5:3b:36:dd:3d:45:48:b0:b0:77:6f:de:58:2a:27:4d:56:
|
|
||||||
20:54:08:20:c8:6d:79:b5:b9:e6:3a:03:24:0f:6d:67:39:20:
|
|
||||||
78:10:2f:47:85:83:c1:4d:17:33:79:84:75:27:fa:47:67:59:
|
|
||||||
56:cc:33:7b:a5:77:aa:59:9a:98:30:10:1a:78:43:34:8f:ed:
|
|
||||||
c2:a1:a3:ea
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET
|
|
||||||
MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp
|
|
||||||
Y2F0ZSBBdXRob3JpdHkxGjAYBgNVBAMMEVByb21ldGhldXMgVExTIENBMCAXDTE5
|
|
||||||
MDQwNTA4MDY1N1oYDzIwNTkwMzI2MDgwNjU3WjBDMQswCQYDVQQGEwJVUzETMBEG
|
|
||||||
A1UECgwKUHJvbWV0aGV1czEfMB0GA1UEAwwWcHJvbWV0aGV1cy5leGFtcGxlLmNv
|
|
||||||
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL1stn/RL77kQetd/1B4
|
|
||||||
Ayt2A9oBSCATkGbJzm4G5fotDcCwRihEEKBheYeimEwp+vm7D0THkFxcVWDNRdq4
|
|
||||||
5N0ocsiLoT5LAAmCsCzc1hfJAvTNJscRKPN3tZfCdsLgB9c0W+DtGlmltLcWCT01
|
|
||||||
vdkDB518O/BjvV4Cmc8y4axMej5Mso6YaAdPWdwNv8yDBFzYkPBz2isIF8Q2p9iU
|
|
||||||
PbbArykK0xlf633MTQVWEQrusfPXyVo8jFcWkVEU+CBODymeBCHm8eToRK/XJZII
|
|
||||||
ZPwsHC5PcVORUx3l+XtSDyHaXN0ZaJbKcGrxxA0Hr/hlE5Lp72WziYb9wHRcpGtJ
|
|
||||||
YsUCAwEAAaOCAREwggENMA4GA1UdDwEB/wQEAwIFoDAJBgNVHRMEAjAAMB0GA1Ud
|
|
||||||
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUAGEBrSVEiu/hLOyD
|
|
||||||
Wjo76qC94UUwHwYDVR0jBBgwFoAUTQK/cZVqqljFnLiDZ15kFpnhKp4wPAYIKwYB
|
|
||||||
BQUHAQEEMDAuMCwGCCsGAQUFBzAChiBodHRwOi8vZXhhbXBsZS5jb20vY2EvdGxz
|
|
||||||
LWNhLmNlcjAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vZXhhbXBsZS5jb20vY2Ev
|
|
||||||
dGxzLWNhLmNybDAgBgNVHREEGTAXhwR/AAABhwR/AAAAgglsb2NhbGhvc3QwDQYJ
|
|
||||||
KoZIhvcNAQEFBQADggEBAHeX5O/bEI5iUJZKbvWk+R8ZO8ik3bP2EUEa++P43Q5k
|
|
||||||
5SsAueYlny7h0prNtvJBTSfdLJqvl3noz2H7z74lxuEZoMiQRKB2ikXUNyLl1IC0
|
|
||||||
sw+oMwgkrSELt5hGk5CKrncMy7hZ0zub+xZaIsrCl514G/wj/KBCVEDeiEsHKxlO
|
|
||||||
Dnm/yZ8BpkbFVfqfwA2KpuFHFqYOviPJ6VjWMXGMgJwWZPAUCCKhI3yYuWLRSs7j
|
|
||||||
XFn7QYelOzbdPUVIsLB3b95YKidNViBUCCDIbXm1ueY6AyQPbWc5IHgQL0eFg8FN
|
|
||||||
FzN5hHUn+kdnWVbMM3uld6pZmpgwEBp4QzSP7cKho+o=
|
|
||||||
-----END CERTIFICATE-----
|
|
28
https/testdata/server.key
vendored
28
https/testdata/server.key
vendored
@ -1,28 +0,0 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9bLZ/0S++5EHr
|
|
||||||
Xf9QeAMrdgPaAUggE5Bmyc5uBuX6LQ3AsEYoRBCgYXmHophMKfr5uw9Ex5BcXFVg
|
|
||||||
zUXauOTdKHLIi6E+SwAJgrAs3NYXyQL0zSbHESjzd7WXwnbC4AfXNFvg7RpZpbS3
|
|
||||||
Fgk9Nb3ZAwedfDvwY71eApnPMuGsTHo+TLKOmGgHT1ncDb/MgwRc2JDwc9orCBfE
|
|
||||||
NqfYlD22wK8pCtMZX+t9zE0FVhEK7rHz18laPIxXFpFRFPggTg8pngQh5vHk6ESv
|
|
||||||
1yWSCGT8LBwuT3FTkVMd5fl7Ug8h2lzdGWiWynBq8cQNB6/4ZROS6e9ls4mG/cB0
|
|
||||||
XKRrSWLFAgMBAAECggEAezQ0V1o11dEc1vuiTjJgzWnLA4aF5OcUquZjb8jo2Blp
|
|
||||||
soR0fUgYEFiV9RRaPl+nr7ptKe0rBgfAOGALKUHNCdN/JNU8oQmjEoyADg3s6jeB
|
|
||||||
xruQlzWgDwszf2uqVwHj16Nkhx1wYBKZQeQBSmCkBHwl/daKHcahqn3CkLOleKx+
|
|
||||||
Qlc3BzWNaGte6qpJMs0It3by1FuxRwVz5VkL8uhzj0WIOYMA84t0gTnFH9gfRO3F
|
|
||||||
licotxg/Nl5M36wWcfL8Jq++72AtaKcD1jUEwuQpogrVeqflmeHwn/TlL++Hv6Xe
|
|
||||||
Lq0jt3OCUKUV40eq9c5uEgTmyrVHMDkfFdXzutdMAQKBgQDsSMXk7P4SX6u6uTjV
|
|
||||||
In9eWw6ZyJ2aL6VB9co/NMsj49GrrFT8VX9d+JPe9P/n6tuGcFbymNep22njRksR
|
|
||||||
0ItpW1NFRR/R3g0kYe1EhkRpNm6fhY9oIuR9xhcNnPNYkqAKT3T/dxrzbwsNhomi
|
|
||||||
X8aht/eCz4ZsK/KdOGTkPozxgQKBgQDNOvrclT1Wl4bxONp9pEV5XpRSD/qigfIp
|
|
||||||
i5wxy7ihX/QY9RToIWJDnzMVLnEYe64RB2WB8/4WwNPOQcuaxXbFUFct/2NdhTnS
|
|
||||||
ToJPgPe819zW9t1FLTf1fHtsRBpGFtbhdlUDOiOtJiMXYiwlRh2uyWFhjOo8TNUE
|
|
||||||
qMwai0vLRQKBgQCDH4t6lC4W4jK5x2oLlT5bjWqX2uXjF8e8x/q5gsGspBPKEjOD
|
|
||||||
aKrq6jSdSRbui73RaGxH6pvb7iBf+LVWKIYFLKIUUdzrqS9f3lw+Z8h1HrjbG9JO
|
|
||||||
dvaX+aL3cf71S0E3F4sU7fLt3tSiZ+PfUQk424+mbyXox6a2qwIKS9AJgQKBgHCu
|
|
||||||
dHROYJo9ojKpo5Ueb6K+4jLYYSV+sYZMCBtzHlFETNKzJaJ6SeiU7Ugw8pmdtqnU
|
|
||||||
5M/gNl8pymFR0MeOqbKWdPdlZJpBfsjQoE2kouEFqFRCwKStui7IBUAheEeJXLv3
|
|
||||||
659U+aek69l35oMkp0GDgjs8UpN/H+pp/36Hgrr9AoGAftWU405rpStHEdRVrazP
|
|
||||||
FibQesT9HOdJgmm1gNIhj+PnFs7lKER9p0Wdl79QnIqjwyhjCXL94TFerzTKLY2c
|
|
||||||
IRj5dcRHiiT0iK8wq8bzGNYCqV73oQXaUFMiutNAArXwzwuvPFPWNBQsjLzeDLeC
|
|
||||||
mcOsCcPAk8cLYtVfZo2sP3g=
|
|
||||||
-----END PRIVATE KEY-----
|
|
173
https/testdata/tls-ca-chain.pem
vendored
173
https/testdata/tls-ca-chain.pem
vendored
@ -1,173 +0,0 @@
|
|||||||
Certificate:
|
|
||||||
Data:
|
|
||||||
Version: 3 (0x2)
|
|
||||||
Serial Number: 2 (0x2)
|
|
||||||
Signature Algorithm: sha1WithRSAEncryption
|
|
||||||
Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA
|
|
||||||
Validity
|
|
||||||
Not Before: Apr 5 08:00:37 2019 GMT
|
|
||||||
Not After : Mar 26 08:00:37 2059 GMT
|
|
||||||
Subject: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus TLS CA
|
|
||||||
Subject Public Key Info:
|
|
||||||
Public Key Algorithm: rsaEncryption
|
|
||||||
RSA Public-Key: (2048 bit)
|
|
||||||
Modulus:
|
|
||||||
00:aa:d2:34:6b:ed:f1:f4:01:08:e5:00:9f:75:c8:
|
|
||||||
ba:fc:4b:72:c6:04:93:af:f1:f6:b5:ce:01:0d:c6:
|
|
||||||
bd:d3:16:98:9d:e5:51:56:12:58:16:ee:18:6e:f0:
|
|
||||||
68:a9:42:16:65:cf:e3:31:f5:90:79:9d:13:32:87:
|
|
||||||
3b:1f:65:fd:84:88:a4:56:3d:26:54:69:05:27:5a:
|
|
||||||
ea:89:02:e7:31:9b:7d:7f:76:93:54:70:bc:17:92:
|
|
||||||
06:9f:9f:90:4a:8a:cf:82:a7:7b:7c:71:c4:fa:34:
|
|
||||||
56:00:32:1a:85:c5:f8:e4:4a:63:43:37:9d:60:84:
|
|
||||||
4d:78:6e:87:12:c4:2b:1f:93:a5:fe:cc:5e:f1:df:
|
|
||||||
c1:97:ff:b7:3e:20:38:1d:71:15:11:ec:6c:7a:cc:
|
|
||||||
0e:87:52:31:b1:b9:74:c3:07:1c:42:4b:1e:c1:17:
|
|
||||||
bc:e4:13:b7:b0:20:2e:c4:07:93:bd:a8:11:f9:da:
|
|
||||||
a7:d0:df:4a:48:be:9b:6d:65:c3:ae:58:56:c0:9f:
|
|
||||||
17:c5:d8:32:b1:04:22:fb:5b:18:f6:20:10:50:ec:
|
|
||||||
2d:10:4f:cc:48:8f:f2:75:dd:33:a4:0e:f5:55:da:
|
|
||||||
2c:89:a1:3a:52:bb:11:11:0b:97:27:17:73:35:da:
|
|
||||||
10:71:b3:9f:a8:42:91:e6:3a:66:00:f9:e5:11:8f:
|
|
||||||
5b:57
|
|
||||||
Exponent: 65537 (0x10001)
|
|
||||||
X509v3 extensions:
|
|
||||||
X509v3 Key Usage: critical
|
|
||||||
Certificate Sign, CRL Sign
|
|
||||||
X509v3 Basic Constraints: critical
|
|
||||||
CA:TRUE, pathlen:0
|
|
||||||
X509v3 Subject Key Identifier:
|
|
||||||
4D:02:BF:71:95:6A:AA:58:C5:9C:B8:83:67:5E:64:16:99:E1:2A:9E
|
|
||||||
X509v3 Authority Key Identifier:
|
|
||||||
keyid:3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A
|
|
||||||
|
|
||||||
Authority Information Access:
|
|
||||||
CA Issuers - URI:https://example.com/ca/root-ca.cer
|
|
||||||
|
|
||||||
X509v3 CRL Distribution Points:
|
|
||||||
|
|
||||||
Full Name:
|
|
||||||
URI:https://example.com/ca/root-ca.crl
|
|
||||||
|
|
||||||
Signature Algorithm: sha1WithRSAEncryption
|
|
||||||
63:fc:ba:30:a5:05:d6:76:14:f1:77:38:b1:41:6f:81:d9:b4:
|
|
||||||
02:fd:bc:e5:f6:d9:e6:73:e0:71:cf:4c:fb:13:b5:6b:bd:b9:
|
|
||||||
c6:f6:28:18:36:e1:8c:d9:93:b3:78:4a:3d:39:1b:f4:fb:69:
|
|
||||||
75:24:ae:e1:a0:2f:94:05:bf:10:3c:3e:d2:2b:a8:f3:31:25:
|
|
||||||
2e:ed:13:ad:60:5d:22:9a:26:15:20:86:98:73:4c:f6:4b:48:
|
|
||||||
b8:1f:67:ba:4e:c9:47:ed:85:dc:38:dc:02:0c:fb:54:d5:2e:
|
|
||||||
6c:b4:95:18:51:d1:ae:ea:e8:fb:b4:19:50:04:bc:31:7e:51:
|
|
||||||
9e:85:29:4d:c8:f7:26:d6:d6:8d:35:2d:9e:e2:06:16:38:e2:
|
|
||||||
56:80:ec:f3:a3:34:e3:28:c4:e8:10:d0:8a:a6:6f:20:9a:b9:
|
|
||||||
dc:b9:90:6b:ba:8a:27:2c:29:72:28:55:e7:59:a6:a7:90:ec:
|
|
||||||
32:e8:d0:26:4a:c1:44:dd:20:bf:dc:4d:1e:7e:cc:e5:a2:5b:
|
|
||||||
e8:df:3d:4b:01:aa:48:56:17:e9:29:d8:71:83:05:36:8c:11:
|
|
||||||
4f:77:b8:95:20:b7:c7:21:06:c2:87:97:b4:6b:d3:f7:23:ba:
|
|
||||||
4d:5f:15:d1:0c:4d:6e:f1:6a:9d:57:5c:02:6a:d7:31:18:ef:
|
|
||||||
5c:fc:f8:04
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIELTCCAxWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJVUzET
|
|
||||||
MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp
|
|
||||||
Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMElByb21ldGhldXMgUm9vdCBDQTAgFw0x
|
|
||||||
OTA0MDUwODAwMzdaGA8yMDU5MDMyNjA4MDAzN1owaTELMAkGA1UEBhMCVVMxEzAR
|
|
||||||
BgNVBAoMClByb21ldGhldXMxKTAnBgNVBAsMIFByb21ldGhldXMgQ2VydGlmaWNh
|
|
||||||
dGUgQXV0aG9yaXR5MRowGAYDVQQDDBFQcm9tZXRoZXVzIFRMUyBDQTCCASIwDQYJ
|
|
||||||
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKrSNGvt8fQBCOUAn3XIuvxLcsYEk6/x
|
|
||||||
9rXOAQ3GvdMWmJ3lUVYSWBbuGG7waKlCFmXP4zH1kHmdEzKHOx9l/YSIpFY9JlRp
|
|
||||||
BSda6okC5zGbfX92k1RwvBeSBp+fkEqKz4Kne3xxxPo0VgAyGoXF+ORKY0M3nWCE
|
|
||||||
TXhuhxLEKx+Tpf7MXvHfwZf/tz4gOB1xFRHsbHrMDodSMbG5dMMHHEJLHsEXvOQT
|
|
||||||
t7AgLsQHk72oEfnap9DfSki+m21lw65YVsCfF8XYMrEEIvtbGPYgEFDsLRBPzEiP
|
|
||||||
8nXdM6QO9VXaLImhOlK7ERELlycXczXaEHGzn6hCkeY6ZgD55RGPW1cCAwEAAaOB
|
|
||||||
3DCB2TAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E
|
|
||||||
FgQUTQK/cZVqqljFnLiDZ15kFpnhKp4wHwYDVR0jBBgwFoAUPB6oxkwFTSDsiNsp
|
|
||||||
1Hv5El3O6howPgYIKwYBBQUHAQEEMjAwMC4GCCsGAQUFBzAChiJodHRwczovL2V4
|
|
||||||
YW1wbGUuY29tL2NhL3Jvb3QtY2EuY2VyMDMGA1UdHwQsMCowKKAmoCSGImh0dHBz
|
|
||||||
Oi8vZXhhbXBsZS5jb20vY2Evcm9vdC1jYS5jcmwwDQYJKoZIhvcNAQEFBQADggEB
|
|
||||||
AGP8ujClBdZ2FPF3OLFBb4HZtAL9vOX22eZz4HHPTPsTtWu9ucb2KBg24YzZk7N4
|
|
||||||
Sj05G/T7aXUkruGgL5QFvxA8PtIrqPMxJS7tE61gXSKaJhUghphzTPZLSLgfZ7pO
|
|
||||||
yUfthdw43AIM+1TVLmy0lRhR0a7q6Pu0GVAEvDF+UZ6FKU3I9ybW1o01LZ7iBhY4
|
|
||||||
4laA7POjNOMoxOgQ0IqmbyCaudy5kGu6iicsKXIoVedZpqeQ7DLo0CZKwUTdIL/c
|
|
||||||
TR5+zOWiW+jfPUsBqkhWF+kp2HGDBTaMEU93uJUgt8chBsKHl7Rr0/cjuk1fFdEM
|
|
||||||
TW7xap1XXAJq1zEY71z8+AQ=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
Certificate:
|
|
||||||
Data:
|
|
||||||
Version: 3 (0x2)
|
|
||||||
Serial Number: 1 (0x1)
|
|
||||||
Signature Algorithm: sha1WithRSAEncryption
|
|
||||||
Issuer: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA
|
|
||||||
Validity
|
|
||||||
Not Before: Apr 5 07:55:00 2019 GMT
|
|
||||||
Not After : Mar 26 07:55:00 2059 GMT
|
|
||||||
Subject: C=US, O=Prometheus, OU=Prometheus Certificate Authority, CN=Prometheus Root CA
|
|
||||||
Subject Public Key Info:
|
|
||||||
Public Key Algorithm: rsaEncryption
|
|
||||||
RSA Public-Key: (2048 bit)
|
|
||||||
Modulus:
|
|
||||||
00:bf:b9:e2:ab:5f:61:22:e1:4e:cd:ee:da:b0:26:
|
|
||||||
2e:bb:b0:7e:1c:ce:10:be:16:29:35:0c:0c:1d:93:
|
|
||||||
01:29:2a:f6:f9:c2:6e:5c:10:44:ca:f8:dc:ad:7a:
|
|
||||||
06:64:0f:8a:18:ad:b2:a2:94:49:c9:ba:8c:45:94:
|
|
||||||
7c:d9:e0:11:45:d8:16:79:a2:20:9f:8c:63:60:72:
|
|
||||||
2a:5b:f9:66:80:ac:85:67:01:5a:eb:91:c1:d2:88:
|
|
||||||
87:9e:4c:18:c9:f2:f0:7a:18:c0:e6:ab:2c:78:de:
|
|
||||||
5f:b2:22:4e:94:9c:f5:cd:e6:e2:33:30:e9:20:10:
|
|
||||||
a6:a1:75:eb:59:ab:45:a9:f7:3e:54:40:ae:05:25:
|
|
||||||
be:74:c5:3a:fd:af:73:16:60:45:7c:4a:e0:0e:0d:
|
|
||||||
a1:15:7f:9a:1f:c2:a7:04:ad:ef:b3:e4:f6:00:2c:
|
|
||||||
4e:0b:04:90:49:ee:d3:db:a6:12:c4:91:0b:32:4f:
|
|
||||||
11:84:c7:c4:8a:ef:51:66:7a:b0:20:2f:cb:95:8d:
|
|
||||||
96:57:60:66:5e:f9:4f:5a:94:9c:71:ad:eb:ca:70:
|
|
||||||
3e:62:06:c2:3a:29:f8:9e:86:af:da:07:78:f8:31:
|
|
||||||
af:42:48:49:9e:4a:df:1b:27:1f:44:35:81:6d:fa:
|
|
||||||
7a:c5:6a:0a:35:23:c7:c4:d5:fe:c9:9e:61:c9:30:
|
|
||||||
cd:1f
|
|
||||||
Exponent: 65537 (0x10001)
|
|
||||||
X509v3 extensions:
|
|
||||||
X509v3 Key Usage: critical
|
|
||||||
Certificate Sign, CRL Sign
|
|
||||||
X509v3 Basic Constraints: critical
|
|
||||||
CA:TRUE
|
|
||||||
X509v3 Subject Key Identifier:
|
|
||||||
3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A
|
|
||||||
X509v3 Authority Key Identifier:
|
|
||||||
keyid:3C:1E:A8:C6:4C:05:4D:20:EC:88:DB:29:D4:7B:F9:12:5D:CE:EA:1A
|
|
||||||
|
|
||||||
Signature Algorithm: sha1WithRSAEncryption
|
|
||||||
56:2f:79:e5:12:91:f5:19:a7:d1:32:28:fd:e3:9d:8f:e1:3c:
|
|
||||||
bb:a3:a5:f2:55:8a:03:ad:2c:1d:18:82:e1:7f:19:75:d9:47:
|
|
||||||
5b:e7:7c:e4:a5:e0:eb:dc:7e:24:a3:7d:99:1a:cf:39:ba:a5:
|
|
||||||
b4:b8:45:68:83:cf:70:ad:56:f2:34:73:65:fc:6c:b0:53:9a:
|
|
||||||
79:04:f7:3e:7e:4b:22:1b:e7:76:23:20:bc:9c:05:a2:5d:01:
|
|
||||||
d2:f0:09:49:17:b2:61:74:1a:5b:f4:e0:fd:ce:11:ba:13:4a:
|
|
||||||
e6:07:11:7d:30:e2:11:87:ee:33:1a:68:de:67:f4:ac:b5:58:
|
|
||||||
1a:ac:cf:7a:2d:fd:c3:44:5b:4b:cd:6c:ff:f6:49:b4:55:4a:
|
|
||||||
09:a0:92:2d:57:3b:69:85:54:3e:e9:ec:ef:b2:a5:7a:29:75:
|
|
||||||
2b:f8:eb:4b:d4:cf:68:ee:3e:c8:63:7e:12:eb:e4:2f:63:a3:
|
|
||||||
a7:c8:0f:e9:39:ff:5c:29:65:7f:25:f0:42:bf:07:ba:06:b8:
|
|
||||||
5e:d6:56:ba:f8:67:56:1b:42:aa:b3:04:d8:6e:88:10:a5:70:
|
|
||||||
b5:81:04:a4:90:a3:f0:83:4d:0c:6b:12:5d:a4:4c:83:5a:ff:
|
|
||||||
a8:7a:86:61:ff:0f:4c:e5:0f:17:d1:64:3c:bd:d9:22:7e:b7:
|
|
||||||
fa:9b:83:ba
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDtDCCApygAwIBAgIBATANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJVUzET
|
|
||||||
MBEGA1UECgwKUHJvbWV0aGV1czEpMCcGA1UECwwgUHJvbWV0aGV1cyBDZXJ0aWZp
|
|
||||||
Y2F0ZSBBdXRob3JpdHkxGzAZBgNVBAMMElByb21ldGhldXMgUm9vdCBDQTAgFw0x
|
|
||||||
OTA0MDUwNzU1MDBaGA8yMDU5MDMyNjA3NTUwMFowajELMAkGA1UEBhMCVVMxEzAR
|
|
||||||
BgNVBAoMClByb21ldGhldXMxKTAnBgNVBAsMIFByb21ldGhldXMgQ2VydGlmaWNh
|
|
||||||
dGUgQXV0aG9yaXR5MRswGQYDVQQDDBJQcm9tZXRoZXVzIFJvb3QgQ0EwggEiMA0G
|
|
||||||
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/ueKrX2Ei4U7N7tqwJi67sH4czhC+
|
|
||||||
Fik1DAwdkwEpKvb5wm5cEETK+NytegZkD4oYrbKilEnJuoxFlHzZ4BFF2BZ5oiCf
|
|
||||||
jGNgcipb+WaArIVnAVrrkcHSiIeeTBjJ8vB6GMDmqyx43l+yIk6UnPXN5uIzMOkg
|
|
||||||
EKahdetZq0Wp9z5UQK4FJb50xTr9r3MWYEV8SuAODaEVf5ofwqcEre+z5PYALE4L
|
|
||||||
BJBJ7tPbphLEkQsyTxGEx8SK71FmerAgL8uVjZZXYGZe+U9alJxxrevKcD5iBsI6
|
|
||||||
Kfiehq/aB3j4Ma9CSEmeSt8bJx9ENYFt+nrFago1I8fE1f7JnmHJMM0fAgMBAAGj
|
|
||||||
YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQ8
|
|
||||||
HqjGTAVNIOyI2ynUe/kSXc7qGjAfBgNVHSMEGDAWgBQ8HqjGTAVNIOyI2ynUe/kS
|
|
||||||
Xc7qGjANBgkqhkiG9w0BAQUFAAOCAQEAVi955RKR9Rmn0TIo/eOdj+E8u6Ol8lWK
|
|
||||||
A60sHRiC4X8ZddlHW+d85KXg69x+JKN9mRrPObqltLhFaIPPcK1W8jRzZfxssFOa
|
|
||||||
eQT3Pn5LIhvndiMgvJwFol0B0vAJSReyYXQaW/Tg/c4RuhNK5gcRfTDiEYfuMxpo
|
|
||||||
3mf0rLVYGqzPei39w0RbS81s//ZJtFVKCaCSLVc7aYVUPuns77Kleil1K/jrS9TP
|
|
||||||
aO4+yGN+EuvkL2Ojp8gP6Tn/XCllfyXwQr8Huga4XtZWuvhnVhtCqrME2G6IEKVw
|
|
||||||
tYEEpJCj8INNDGsSXaRMg1r/qHqGYf8PTOUPF9FkPL3ZIn63+puDug==
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,4 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_ca_file : "somefile"
|
|
@ -1,4 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "RequireAndVerifyClientCert"
|
|
@ -1,5 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
basic_auth_users:
|
|
||||||
john: doe
|
|
0
https/testdata/tls_config_empty.yml
vendored
0
https/testdata/tls_config_empty.yml
vendored
20
https/testdata/tls_config_junk.yml
vendored
20
https/testdata/tls_config_junk.yml
vendored
@ -1,20 +0,0 @@
|
|||||||
hWkNKCp3fvIx3jKnsaBI
|
|
||||||
TuEjdwNS8A2vYdFbiKqr
|
|
||||||
ay3RiOtykgt4m6m3KOol
|
|
||||||
ZreGpJRGmpDSVV9cioiF
|
|
||||||
r7kDOHhHU2frvv0nLcY2
|
|
||||||
uQMQM4XgqFkCG6gFAIJZ
|
|
||||||
g99tTkrZhN9b6pkJ6J2y
|
|
||||||
rzdt729HrA2RblDGYfjs
|
|
||||||
MW7GxrBdlCnliYJGPhfr
|
|
||||||
g9kaXxMXcDwsw0C0rv0u
|
|
||||||
637ZmfRGElb6VBVOtgqn
|
|
||||||
RG0MRezjLYCJQBMUdRDE
|
|
||||||
RzO4VicAzj7asVZAT3oo
|
|
||||||
nPw267UONk7h7KBYRgch
|
|
||||||
Alj38foWqjV3heXXdahm
|
|
||||||
TrMzMgl6JIQ1x4OZB5i4
|
|
||||||
qlrXFJoeV6Pr77nuiEh9
|
|
||||||
3yE5vMnnKHm2nImEfzMG
|
|
||||||
bI01UDObHRSaoJLC0vTD
|
|
||||||
G9tlcKU883NkQ6nsxJ8Y
|
|
2
https/testdata/tls_config_junk_key.yml
vendored
2
https/testdata/tls_config_junk_key.yml
vendored
@ -1,2 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_filse: "testdata/server.crt"
|
|
4
https/testdata/tls_config_noAuth.bad.yml
vendored
4
https/testdata/tls_config_noAuth.bad.yml
vendored
@ -1,4 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
@ -1,5 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "RequireAndVerifyClientCert"
|
|
||||||
client_ca_file: "testdata/tls-ca-chain.pem"
|
|
5
https/testdata/tls_config_noAuth.good.yml
vendored
5
https/testdata/tls_config_noAuth.good.yml
vendored
@ -1,5 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
@ -1,26 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
cipher_suites:
|
|
||||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
|
||||||
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
||||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
|
||||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
|
||||||
- TLS_AES_128_GCM_SHA256
|
|
||||||
- TLS_AES_256_GCM_SHA384
|
|
||||||
- TLS_CHACHA20_POLY1305_SHA256
|
|
||||||
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
|
||||||
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
|
||||||
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
|
||||||
- TLS_RSA_WITH_3DES_EDE_CBC_SHA
|
|
||||||
- TLS_RSA_WITH_AES_128_CBC_SHA
|
|
||||||
- TLS_RSA_WITH_AES_256_CBC_SHA
|
|
||||||
- TLS_RSA_WITH_AES_128_GCM_SHA256
|
|
||||||
- TLS_RSA_WITH_AES_256_GCM_SHA384
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
curve_preferences:
|
|
||||||
- CurveP256
|
|
||||||
- CurveP384
|
|
||||||
- CurveP521
|
|
||||||
- X25519
|
|
@ -1,3 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : ""
|
|
||||||
key_file : "testdata/server.key"
|
|
@ -1,3 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "somefile"
|
|
||||||
key_file : "testdata/server.key"
|
|
@ -1,4 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : ""
|
|
||||||
key_file : ""
|
|
||||||
client_auth_type: "x"
|
|
@ -1,3 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "somefile"
|
|
||||||
key_file : "somefile"
|
|
@ -1,8 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
cipher_suites:
|
|
||||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA2048
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
curve_preferences:
|
|
||||||
- CurveP257
|
|
@ -1,3 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : ""
|
|
@ -1,3 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.cert"
|
|
||||||
key_file : "somefile"
|
|
@ -1,10 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
cipher_suites:
|
|
||||||
- TLS_RSA_WITH_AES_128_CBC_SHA
|
|
||||||
max_version: TLS12
|
|
||||||
http_server_config:
|
|
||||||
http2: false
|
|
@ -1,8 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
cipher_suites:
|
|
||||||
- TLS_RSA_WITH_AES_128_CBC_SHA
|
|
||||||
max_version: TLS12
|
|
@ -1,10 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
cipher_suites:
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
||||||
min_version: TLS12
|
|
||||||
max_version: TLS12
|
|
@ -1,11 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
cipher_suites:
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
|
||||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
|
||||||
prefer_server_cipher_suites: false
|
|
||||||
min_version: TLS12
|
|
||||||
max_version: TLS12
|
|
@ -1,8 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
min_version: TLS13
|
|
||||||
curve_preferences:
|
|
||||||
- CurveP521
|
|
@ -1,6 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
client_auth_type : "VerifyClientCertIfGiven"
|
|
||||||
client_ca_file : "testdata/tls-ca-chain.pem"
|
|
||||||
min_version: TLS111
|
|
8
https/testdata/tls_config_users.good.yml
vendored
8
https/testdata/tls_config_users.good.yml
vendored
@ -1,8 +0,0 @@
|
|||||||
tls_server_config :
|
|
||||||
cert_file : "testdata/server.crt"
|
|
||||||
key_file : "testdata/server.key"
|
|
||||||
basic_auth_users:
|
|
||||||
alice: $2y$12$1DpfPeqF9HzHJt.EWswy1exHluGfbhnn3yXhR7Xes6m3WJqFg0Wby
|
|
||||||
bob: $2y$18$4VeFDzXIoPHKnKTU3O3GH.N.vZu06CVqczYZ8WvfzrddFU6tGqjR.
|
|
||||||
carol: $2y$10$qRTBuFoULoYNA7AQ/F3ck.trZBPyjV64.oA4ZsSBCIWvXuvQlQTuu
|
|
||||||
dave: $2y$10$2UXri9cIDdgeKjBo4Rlpx.U3ZLDV8X1IxKmsfOvhcM5oXQt/mLmXq
|
|
@ -1,5 +0,0 @@
|
|||||||
basic_auth_users:
|
|
||||||
alice: $2y$12$1DpfPeqF9HzHJt.EWswy1exHluGfbhnn3yXhR7Xes6m3WJqFg0Wby
|
|
||||||
bob: $2y$18$4VeFDzXIoPHKnKTU3O3GH.N.vZu06CVqczYZ8WvfzrddFU6tGqjR.
|
|
||||||
carol: $2y$10$qRTBuFoULoYNA7AQ/F3ck.trZBPyjV64.oA4ZsSBCIWvXuvQlQTuu
|
|
||||||
dave: $2y$10$2UXri9cIDdgeKjBo4Rlpx.U3ZLDV8X1IxKmsfOvhcM5oXQt/mLmXq
|
|
@ -1,301 +0,0 @@
|
|||||||
// Copyright 2019 The Prometheus Authors
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Package https allows the implementation of TLS.
|
|
||||||
package https
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/go-kit/kit/log"
|
|
||||||
"github.com/go-kit/kit/log/level"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
config_util "github.com/prometheus/common/config"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errNoTLSConfig = errors.New("TLS config is not present")
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
TLSConfig TLSStruct `yaml:"tls_server_config"`
|
|
||||||
HTTPConfig HTTPStruct `yaml:"http_server_config"`
|
|
||||||
Users map[string]config_util.Secret `yaml:"basic_auth_users"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TLSStruct struct {
|
|
||||||
TLSCertPath string `yaml:"cert_file"`
|
|
||||||
TLSKeyPath string `yaml:"key_file"`
|
|
||||||
ClientAuth string `yaml:"client_auth_type"`
|
|
||||||
ClientCAs string `yaml:"client_ca_file"`
|
|
||||||
CipherSuites []cipher `yaml:"cipher_suites"`
|
|
||||||
CurvePreferences []curve `yaml:"curve_preferences"`
|
|
||||||
MinVersion tlsVersion `yaml:"min_version"`
|
|
||||||
MaxVersion tlsVersion `yaml:"max_version"`
|
|
||||||
PreferServerCipherSuites bool `yaml:"prefer_server_cipher_suites"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HTTPStruct struct {
|
|
||||||
HTTP2 bool `yaml:"http2"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getConfig(configPath string) (*Config, error) {
|
|
||||||
content, err := ioutil.ReadFile(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c := &Config{
|
|
||||||
TLSConfig: TLSStruct{
|
|
||||||
MinVersion: tls.VersionTLS12,
|
|
||||||
MaxVersion: tls.VersionTLS13,
|
|
||||||
PreferServerCipherSuites: true,
|
|
||||||
},
|
|
||||||
HTTPConfig: HTTPStruct{HTTP2: true},
|
|
||||||
}
|
|
||||||
err = yaml.UnmarshalStrict(content, c)
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTLSConfig(configPath string) (*tls.Config, error) {
|
|
||||||
c, err := getConfig(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ConfigToTLSConfig(&c.TLSConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigToTLSConfig generates the golang tls.Config from the TLSStruct config.
|
|
||||||
func ConfigToTLSConfig(c *TLSStruct) (*tls.Config, error) {
|
|
||||||
if c.TLSCertPath == "" && c.TLSKeyPath == "" && c.ClientAuth == "" && c.ClientCAs == "" {
|
|
||||||
return nil, errNoTLSConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.TLSCertPath == "" {
|
|
||||||
return nil, errors.New("missing cert_file")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.TLSKeyPath == "" {
|
|
||||||
return nil, errors.New("missing key_file")
|
|
||||||
}
|
|
||||||
|
|
||||||
loadCert := func() (*tls.Certificate, error) {
|
|
||||||
cert, err := tls.LoadX509KeyPair(c.TLSCertPath, c.TLSKeyPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "failed to load X509KeyPair")
|
|
||||||
}
|
|
||||||
return &cert, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm that certificate and key paths are valid.
|
|
||||||
if _, err := loadCert(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := &tls.Config{
|
|
||||||
MinVersion: (uint16)(c.MinVersion),
|
|
||||||
MaxVersion: (uint16)(c.MaxVersion),
|
|
||||||
PreferServerCipherSuites: c.PreferServerCipherSuites,
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
|
|
||||||
return loadCert()
|
|
||||||
}
|
|
||||||
|
|
||||||
var cf []uint16
|
|
||||||
for _, c := range c.CipherSuites {
|
|
||||||
cf = append(cf, (uint16)(c))
|
|
||||||
}
|
|
||||||
if len(cf) > 0 {
|
|
||||||
cfg.CipherSuites = cf
|
|
||||||
}
|
|
||||||
|
|
||||||
var cp []tls.CurveID
|
|
||||||
for _, c := range c.CurvePreferences {
|
|
||||||
cp = append(cp, (tls.CurveID)(c))
|
|
||||||
}
|
|
||||||
if len(cp) > 0 {
|
|
||||||
cfg.CurvePreferences = cp
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ClientCAs != "" {
|
|
||||||
clientCAPool := x509.NewCertPool()
|
|
||||||
clientCAFile, err := ioutil.ReadFile(c.ClientCAs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
clientCAPool.AppendCertsFromPEM(clientCAFile)
|
|
||||||
cfg.ClientCAs = clientCAPool
|
|
||||||
}
|
|
||||||
|
|
||||||
switch c.ClientAuth {
|
|
||||||
case "RequestClientCert":
|
|
||||||
cfg.ClientAuth = tls.RequestClientCert
|
|
||||||
case "RequireClientCert":
|
|
||||||
cfg.ClientAuth = tls.RequireAnyClientCert
|
|
||||||
case "VerifyClientCertIfGiven":
|
|
||||||
cfg.ClientAuth = tls.VerifyClientCertIfGiven
|
|
||||||
case "RequireAndVerifyClientCert":
|
|
||||||
cfg.ClientAuth = tls.RequireAndVerifyClientCert
|
|
||||||
case "", "NoClientCert":
|
|
||||||
cfg.ClientAuth = tls.NoClientCert
|
|
||||||
default:
|
|
||||||
return nil, errors.New("Invalid ClientAuth: " + c.ClientAuth)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ClientCAs != "" && cfg.ClientAuth == tls.NoClientCert {
|
|
||||||
return nil, errors.New("Client CA's have been configured without a Client Auth Policy")
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen starts the server on the given address. If tlsConfigPath isn't empty the server connection will be started using TLS.
|
|
||||||
func Listen(server *http.Server, tlsConfigPath string, logger log.Logger) error {
|
|
||||||
if tlsConfigPath == "" {
|
|
||||||
level.Info(logger).Log("msg", "TLS is disabled.", "http2", false)
|
|
||||||
return server.ListenAndServe()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateUsers(tlsConfigPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup basic authentication.
|
|
||||||
var handler http.Handler = http.DefaultServeMux
|
|
||||||
if server.Handler != nil {
|
|
||||||
handler = server.Handler
|
|
||||||
}
|
|
||||||
server.Handler = &userAuthRoundtrip{
|
|
||||||
tlsConfigPath: tlsConfigPath,
|
|
||||||
logger: logger,
|
|
||||||
handler: handler,
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := getConfig(tlsConfigPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
config, err := ConfigToTLSConfig(&c.TLSConfig)
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
if !c.HTTPConfig.HTTP2 {
|
|
||||||
server.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))
|
|
||||||
}
|
|
||||||
// Valid TLS config.
|
|
||||||
level.Info(logger).Log("msg", "TLS is enabled.", "http2", c.HTTPConfig.HTTP2)
|
|
||||||
case errNoTLSConfig:
|
|
||||||
// No TLS config, back to plain HTTP.
|
|
||||||
level.Info(logger).Log("msg", "TLS is disabled.", "http2", false)
|
|
||||||
return server.ListenAndServe()
|
|
||||||
default:
|
|
||||||
// Invalid TLS config.
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
server.TLSConfig = config
|
|
||||||
|
|
||||||
// Set the GetConfigForClient method of the HTTPS server so that the config
|
|
||||||
// and certs are reloaded on new connections.
|
|
||||||
server.TLSConfig.GetConfigForClient = func(*tls.ClientHelloInfo) (*tls.Config, error) {
|
|
||||||
return getTLSConfig(tlsConfigPath)
|
|
||||||
}
|
|
||||||
return server.ListenAndServeTLS("", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
type cipher uint16
|
|
||||||
|
|
||||||
func (c *cipher) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var s string
|
|
||||||
err := unmarshal((*string)(&s))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, cs := range tls.CipherSuites() {
|
|
||||||
if cs.Name == s {
|
|
||||||
*c = (cipher)(cs.ID)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.New("unknown cipher: " + s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c cipher) MarshalYAML() (interface{}, error) {
|
|
||||||
return tls.CipherSuiteName((uint16)(c)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type curve tls.CurveID
|
|
||||||
|
|
||||||
var curves = map[string]curve{
|
|
||||||
"CurveP256": (curve)(tls.CurveP256),
|
|
||||||
"CurveP384": (curve)(tls.CurveP384),
|
|
||||||
"CurveP521": (curve)(tls.CurveP521),
|
|
||||||
"X25519": (curve)(tls.X25519),
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *curve) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var s string
|
|
||||||
err := unmarshal((*string)(&s))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if curveid, ok := curves[s]; ok {
|
|
||||||
*c = curveid
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New("unknown curve: " + s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *curve) MarshalYAML() (interface{}, error) {
|
|
||||||
for s, curveid := range curves {
|
|
||||||
if *c == curveid {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%v", c), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type tlsVersion uint16
|
|
||||||
|
|
||||||
var tlsVersions = map[string]tlsVersion{
|
|
||||||
"TLS13": (tlsVersion)(tls.VersionTLS13),
|
|
||||||
"TLS12": (tlsVersion)(tls.VersionTLS12),
|
|
||||||
"TLS11": (tlsVersion)(tls.VersionTLS11),
|
|
||||||
"TLS10": (tlsVersion)(tls.VersionTLS10),
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tv *tlsVersion) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var s string
|
|
||||||
err := unmarshal((*string)(&s))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if v, ok := tlsVersions[s]; ok {
|
|
||||||
*tv = v
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New("unknown TLS version: " + s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tv *tlsVersion) MarshalYAML() (interface{}, error) {
|
|
||||||
for s, v := range tlsVersions {
|
|
||||||
if *tv == v {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%v", tv), nil
|
|
||||||
}
|
|
@ -1,577 +0,0 @@
|
|||||||
// Copyright 2019 The Prometheus Authors
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// +build go1.14
|
|
||||||
|
|
||||||
package https
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
port = getPort()
|
|
||||||
testlogger = &testLogger{}
|
|
||||||
|
|
||||||
ErrorMap = map[string]*regexp.Regexp{
|
|
||||||
"HTTP Response to HTTPS": regexp.MustCompile(`server gave HTTP response to HTTPS client`),
|
|
||||||
"No such file": regexp.MustCompile(`no such file`),
|
|
||||||
"Invalid argument": regexp.MustCompile(`invalid argument`),
|
|
||||||
"YAML error": regexp.MustCompile(`yaml`),
|
|
||||||
"Invalid ClientAuth": regexp.MustCompile(`invalid ClientAuth`),
|
|
||||||
"TLS handshake": regexp.MustCompile(`tls`),
|
|
||||||
"HTTP Request to HTTPS server": regexp.MustCompile(`HTTP`),
|
|
||||||
"Invalid CertPath": regexp.MustCompile(`missing cert_file`),
|
|
||||||
"Invalid KeyPath": regexp.MustCompile(`missing key_file`),
|
|
||||||
"ClientCA set without policy": regexp.MustCompile(`Client CA's have been configured without a Client Auth Policy`),
|
|
||||||
"Bad password": regexp.MustCompile(`hashedSecret too short to be a bcrypted password`),
|
|
||||||
"Unauthorized": regexp.MustCompile(`Unauthorized`),
|
|
||||||
"Forbidden": regexp.MustCompile(`Forbidden`),
|
|
||||||
"Handshake failure": regexp.MustCompile(`handshake failure`),
|
|
||||||
"Unknown cipher": regexp.MustCompile(`unknown cipher`),
|
|
||||||
"Unknown curve": regexp.MustCompile(`unknown curve`),
|
|
||||||
"Unknown TLS version": regexp.MustCompile(`unknown TLS version`),
|
|
||||||
"No HTTP2 cipher": regexp.MustCompile(`TLSConfig.CipherSuites is missing an HTTP/2-required`),
|
|
||||||
"Incompatible TLS version": regexp.MustCompile(`protocol version not supported`),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type testLogger struct{}
|
|
||||||
|
|
||||||
func (t *testLogger) Log(keyvals ...interface{}) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPort() string {
|
|
||||||
listener, err := net.Listen("tcp", ":0")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer listener.Close()
|
|
||||||
p := listener.Addr().(*net.TCPAddr).Port
|
|
||||||
return fmt.Sprintf(":%v", p)
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestInputs struct {
|
|
||||||
Name string
|
|
||||||
Server func() *http.Server
|
|
||||||
UseNilServer bool
|
|
||||||
YAMLConfigPath string
|
|
||||||
ExpectedError *regexp.Regexp
|
|
||||||
UseTLSClient bool
|
|
||||||
ClientMaxTLSVersion uint16
|
|
||||||
CipherSuites []uint16
|
|
||||||
ActualCipher uint16
|
|
||||||
CurvePreferences []tls.CurveID
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestYAMLFiles(t *testing.T) {
|
|
||||||
testTables := []*TestInputs{
|
|
||||||
{
|
|
||||||
Name: `path to config yml invalid`,
|
|
||||||
YAMLConfigPath: "somefile",
|
|
||||||
ExpectedError: ErrorMap["No such file"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `empty config yml`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_empty.yml",
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (invalid structure)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_junk.yml",
|
|
||||||
ExpectedError: ErrorMap["YAML error"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (invalid key)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_junk_key.yml",
|
|
||||||
ExpectedError: ErrorMap["YAML error"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (cert path empty)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_certPath_empty.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["Invalid CertPath"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (key path empty)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_keyPath_empty.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["Invalid KeyPath"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (cert path and key path empty)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_certPath_keyPath_empty.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["Invalid CertPath"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (cert path invalid)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_certPath_invalid.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["No such file"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (key path invalid)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_keyPath_invalid.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["No such file"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (cert path and key path invalid)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_certPath_keyPath_invalid.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["No such file"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (invalid ClientAuth)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["ClientCA set without policy"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (invalid ClientCAs filepath)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_auth_clientCAs_invalid.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["No such file"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (invalid user list)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_auth_user_list_invalid.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["Bad password"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (bad cipher)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_inventedCiphers.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["Unknown cipher"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (bad curves)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_inventedCurves.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["Unknown curve"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `invalid config yml (bad TLS version)`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_wrongTLSVersion.bad.yml",
|
|
||||||
ExpectedError: ErrorMap["Unknown TLS version"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, testInputs := range testTables {
|
|
||||||
t.Run(testInputs.Name, testInputs.Test)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServerBehaviour(t *testing.T) {
|
|
||||||
testTables := []*TestInputs{
|
|
||||||
{
|
|
||||||
Name: `empty string YAMLConfigPath and default client`,
|
|
||||||
YAMLConfigPath: "",
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `empty string YAMLConfigPath and TLS client`,
|
|
||||||
YAMLConfigPath: "",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ExpectedError: ErrorMap["HTTP Response to HTTPS"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml and default client`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth.good.yml",
|
|
||||||
ExpectedError: ErrorMap["HTTP Request to HTTPS server"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml and tls client`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with TLS 1.1 client`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ClientMaxTLSVersion: tls.VersionTLS11,
|
|
||||||
ExpectedError: ErrorMap["Incompatible TLS version"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with all ciphers`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_allCiphers.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with some ciphers`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with no common cipher`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
|
|
||||||
ExpectedError: ErrorMap["Handshake failure"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with multiple client ciphers`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
CipherSuites: []uint16{
|
|
||||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
||||||
},
|
|
||||||
ActualCipher: tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with multiple client ciphers, client chooses cipher`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_someCiphers_noOrder.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
CipherSuites: []uint16{
|
|
||||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
||||||
},
|
|
||||||
ActualCipher: tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with all curves`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_allCurves.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with some curves`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_someCurves.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
CurvePreferences: []tls.CurveID{tls.CurveP521},
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with no common curves`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_someCurves.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
CurvePreferences: []tls.CurveID{tls.CurveP384},
|
|
||||||
ExpectedError: ErrorMap["Handshake failure"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with non-http2 ciphers`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_noHTTP2.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `valid tls config yml with non-http2 ciphers but http2 enabled`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_noAuth_noHTTP2Cipher.bad.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ExpectedError: ErrorMap["No HTTP2 cipher"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, testInputs := range testTables {
|
|
||||||
t.Run(testInputs.Name, testInputs.Test)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigReloading(t *testing.T) {
|
|
||||||
errorChannel := make(chan error, 1)
|
|
||||||
var once sync.Once
|
|
||||||
recordConnectionError := func(err error) {
|
|
||||||
once.Do(func() {
|
|
||||||
errorChannel <- err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if recover() != nil {
|
|
||||||
recordConnectionError(errors.New("Panic in test function"))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
goodYAMLPath := "testdata/tls_config_noAuth.good.yml"
|
|
||||||
badYAMLPath := "testdata/tls_config_noAuth.good.blocking.yml"
|
|
||||||
|
|
||||||
server := &http.Server{
|
|
||||||
Addr: port,
|
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Write([]byte("Hello World!"))
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
server.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
if recover() != nil {
|
|
||||||
recordConnectionError(errors.New("Panic starting server"))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err := Listen(server, badYAMLPath, testlogger)
|
|
||||||
recordConnectionError(err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
client := getTLSClient()
|
|
||||||
|
|
||||||
TestClientConnection := func() error {
|
|
||||||
time.Sleep(250 * time.Millisecond)
|
|
||||||
r, err := client.Get("https://localhost" + port)
|
|
||||||
if err != nil {
|
|
||||||
return (err)
|
|
||||||
}
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
return (err)
|
|
||||||
}
|
|
||||||
if string(body) != "Hello World!" {
|
|
||||||
return (errors.New(string(body)))
|
|
||||||
}
|
|
||||||
return (nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := TestClientConnection()
|
|
||||||
if err == nil {
|
|
||||||
recordConnectionError(errors.New("connection accepted but should have failed"))
|
|
||||||
} else {
|
|
||||||
swapFileContents(goodYAMLPath, badYAMLPath)
|
|
||||||
defer swapFileContents(goodYAMLPath, badYAMLPath)
|
|
||||||
err = TestClientConnection()
|
|
||||||
if err != nil {
|
|
||||||
recordConnectionError(errors.New("connection failed but should have been accepted"))
|
|
||||||
} else {
|
|
||||||
|
|
||||||
recordConnectionError(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = <-errorChannel
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf(" *** Failed test: %s *** Returned error: %v", "TestConfigReloading", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (test *TestInputs) Test(t *testing.T) {
|
|
||||||
errorChannel := make(chan error, 1)
|
|
||||||
var once sync.Once
|
|
||||||
recordConnectionError := func(err error) {
|
|
||||||
once.Do(func() {
|
|
||||||
errorChannel <- err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if recover() != nil {
|
|
||||||
recordConnectionError(errors.New("Panic in test function"))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var server *http.Server
|
|
||||||
if test.UseNilServer {
|
|
||||||
server = nil
|
|
||||||
} else {
|
|
||||||
server = &http.Server{
|
|
||||||
Addr: port,
|
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Write([]byte("Hello World!"))
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
server.Close()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
if recover() != nil {
|
|
||||||
recordConnectionError(errors.New("Panic starting server"))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err := Listen(server, test.YAMLConfigPath, testlogger)
|
|
||||||
recordConnectionError(err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ClientConnection := func() (*http.Response, error) {
|
|
||||||
var client *http.Client
|
|
||||||
var proto string
|
|
||||||
if test.UseTLSClient {
|
|
||||||
client = getTLSClient()
|
|
||||||
t := client.Transport.(*http.Transport)
|
|
||||||
t.TLSClientConfig.MaxVersion = test.ClientMaxTLSVersion
|
|
||||||
if len(test.CipherSuites) > 0 {
|
|
||||||
t.TLSClientConfig.CipherSuites = test.CipherSuites
|
|
||||||
}
|
|
||||||
if len(test.CurvePreferences) > 0 {
|
|
||||||
t.TLSClientConfig.CurvePreferences = test.CurvePreferences
|
|
||||||
}
|
|
||||||
proto = "https"
|
|
||||||
} else {
|
|
||||||
client = http.DefaultClient
|
|
||||||
proto = "http"
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest("GET", proto+"://localhost"+port, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
if test.Username != "" {
|
|
||||||
req.SetBasicAuth(test.Username, test.Password)
|
|
||||||
}
|
|
||||||
return client.Do(req)
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
time.Sleep(250 * time.Millisecond)
|
|
||||||
r, err := ClientConnection()
|
|
||||||
if err != nil {
|
|
||||||
recordConnectionError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if test.ActualCipher != 0 {
|
|
||||||
if r.TLS.CipherSuite != test.ActualCipher {
|
|
||||||
recordConnectionError(
|
|
||||||
fmt.Errorf("bad cipher suite selected. Expected: %s, got: %s",
|
|
||||||
tls.CipherSuiteName(r.TLS.CipherSuite),
|
|
||||||
tls.CipherSuiteName(test.ActualCipher),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
recordConnectionError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if string(body) != "Hello World!" {
|
|
||||||
recordConnectionError(errors.New(string(body)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
recordConnectionError(nil)
|
|
||||||
}()
|
|
||||||
err := <-errorChannel
|
|
||||||
if test.isCorrectError(err) == false {
|
|
||||||
if test.ExpectedError == nil {
|
|
||||||
t.Logf("Expected no error, got error: %v", err)
|
|
||||||
} else {
|
|
||||||
t.Logf("Expected error matching regular expression: %v", test.ExpectedError)
|
|
||||||
t.Logf("Got: %v", err)
|
|
||||||
}
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (test *TestInputs) isCorrectError(returnedError error) bool {
|
|
||||||
switch {
|
|
||||||
case returnedError == nil && test.ExpectedError == nil:
|
|
||||||
case returnedError != nil && test.ExpectedError != nil && test.ExpectedError.MatchString(returnedError.Error()):
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTLSClient() *http.Client {
|
|
||||||
cert, err := ioutil.ReadFile("testdata/tls-ca-chain.pem")
|
|
||||||
if err != nil {
|
|
||||||
panic("Unable to start TLS client. Check cert path")
|
|
||||||
}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
RootCAs: func() *x509.CertPool {
|
|
||||||
caCertPool := x509.NewCertPool()
|
|
||||||
caCertPool.AppendCertsFromPEM(cert)
|
|
||||||
return caCertPool
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return client
|
|
||||||
}
|
|
||||||
|
|
||||||
func swapFileContents(file1, file2 string) error {
|
|
||||||
content1, err := ioutil.ReadFile(file1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
content2, err := ioutil.ReadFile(file2)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(file1, content2, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = ioutil.WriteFile(file2, content1, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUsers(t *testing.T) {
|
|
||||||
testTables := []*TestInputs{
|
|
||||||
{
|
|
||||||
Name: `without basic auth`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_users_noTLS.good.yml",
|
|
||||||
ExpectedError: ErrorMap["Unauthorized"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `with correct basic auth`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_users_noTLS.good.yml",
|
|
||||||
Username: "dave",
|
|
||||||
Password: "dave123",
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `without basic auth and TLS`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_users.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
ExpectedError: ErrorMap["Unauthorized"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `with correct basic auth and TLS`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_users.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
Username: "dave",
|
|
||||||
Password: "dave123",
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `with another correct basic auth and TLS`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_users.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
Username: "carol",
|
|
||||||
Password: "carol123",
|
|
||||||
ExpectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `with bad password and TLS`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_users.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
Username: "dave",
|
|
||||||
Password: "bad",
|
|
||||||
ExpectedError: ErrorMap["Forbidden"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: `with bad username and TLS`,
|
|
||||||
YAMLConfigPath: "testdata/tls_config_users.good.yml",
|
|
||||||
UseTLSClient: true,
|
|
||||||
Username: "nonexistent",
|
|
||||||
Password: "nonexistent",
|
|
||||||
ExpectedError: ErrorMap["Forbidden"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, testInputs := range testTables {
|
|
||||||
t.Run(testInputs.Name, testInputs.Test)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
// Copyright 2020 The Prometheus Authors
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package https
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/go-kit/kit/log"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func validateUsers(configPath string) error {
|
|
||||||
c, err := getConfig(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range c.Users {
|
|
||||||
_, err = bcrypt.Cost([]byte(p))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type userAuthRoundtrip struct {
|
|
||||||
tlsConfigPath string
|
|
||||||
handler http.Handler
|
|
||||||
logger log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *userAuthRoundtrip) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
c, err := getConfig(u.tlsConfigPath)
|
|
||||||
if err != nil {
|
|
||||||
u.logger.Log("msg", "Unable to parse configuration", "err", err)
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.Users) == 0 {
|
|
||||||
u.handler.ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
user, pass, ok := r.BasicAuth()
|
|
||||||
if !ok {
|
|
||||||
w.Header().Set("WWW-Authenticate", "Basic")
|
|
||||||
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if hashedPassword, ok := c.Users[user]; ok {
|
|
||||||
if err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(pass)); err == nil {
|
|
||||||
u.handler.ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
# Minimal TLS configuration example. Additionally, a certificate and a key file
|
|
||||||
# are needed.
|
|
||||||
tls_server_config:
|
|
||||||
cert_file: server.crt
|
|
||||||
key_file: server.key
|
|
||||||
|
|
@ -18,6 +18,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
|
"os/user"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/prometheus/common/promlog"
|
"github.com/prometheus/common/promlog"
|
||||||
@ -28,8 +29,8 @@ import (
|
|||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/prometheus/common/version"
|
"github.com/prometheus/common/version"
|
||||||
|
"github.com/prometheus/exporter-toolkit/web"
|
||||||
"github.com/prometheus/node_exporter/collector"
|
"github.com/prometheus/node_exporter/collector"
|
||||||
"github.com/prometheus/node_exporter/https"
|
|
||||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -176,6 +177,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
level.Info(logger).Log("msg", "Starting node_exporter", "version", version.Info())
|
level.Info(logger).Log("msg", "Starting node_exporter", "version", version.Info())
|
||||||
level.Info(logger).Log("msg", "Build context", "build_context", version.BuildContext())
|
level.Info(logger).Log("msg", "Build context", "build_context", version.BuildContext())
|
||||||
|
if user, err := user.Current(); err == nil && user.Uid == "0" {
|
||||||
|
level.Warn(logger).Log("msg", "Node Exporter is running as root user. This exporter is designed to run as unpriviledged user, root is not required.")
|
||||||
|
}
|
||||||
|
|
||||||
http.Handle(*metricsPath, newHandler(!*disableExporterMetrics, *maxRequests, logger))
|
http.Handle(*metricsPath, newHandler(!*disableExporterMetrics, *maxRequests, logger))
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -190,7 +194,7 @@ func main() {
|
|||||||
|
|
||||||
level.Info(logger).Log("msg", "Listening on", "address", *listenAddress)
|
level.Info(logger).Log("msg", "Listening on", "address", *listenAddress)
|
||||||
server := &http.Server{Addr: *listenAddress}
|
server := &http.Server{Addr: *listenAddress}
|
||||||
if err := https.Listen(server, *configFile, logger); err != nil {
|
if err := web.ListenAndServe(server, *configFile, logger); err != nil {
|
||||||
level.Error(logger).Log("err", err)
|
level.Error(logger).Log("err", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user