Skip to content

Commit

Permalink
Merge pull request #3 from Abbas-gheydi/release-1-1-0-with-team-label
Browse files Browse the repository at this point in the history
Release 1 1 0 with team label
  • Loading branch information
abbas-gheydi authored Jul 7, 2023
2 parents f60affb + bb80e54 commit d7cc2d3
Show file tree
Hide file tree
Showing 10 changed files with 389 additions and 8 deletions.
17 changes: 17 additions & 0 deletions .github/actionlint-matcher.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"problemMatcher": [
{
"owner": "actionlint",
"pattern": [
{
"regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$",
"file": 1,
"line": 2,
"column": 3,
"message": 4,
"code": 5
}
]
}
]
}
16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
63 changes: 63 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
name: ci
on:
push:
branches: [ main, "release-" ]
tags: [ v* ]

jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: latest
test:
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.19'
- run: go test -v ./... -covermode=atomic -coverprofile=coverage.out
- uses: codecov/codecov-action@v1
with:
files: coverage.out
docker:
name: docker
runs-on: ubuntu-latest
needs:
- lint
- test
steps:
- uses: actions/checkout@v2
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v3
id: meta
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- uses: docker/build-push-action@v2
with:
file: "Dockerfile"
context: .
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}


47 changes: 47 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Lint PRs
on:
pull_request:
workflow_dispatch:

jobs:

hadolint-pr:
runs-on: ubuntu-latest
name: PR - Hadolint
steps:
- uses: actions/checkout@v3
- uses: reviewdog/action-hadolint@v1

shellcheck-pr:
runs-on: ubuntu-latest
name: PR - Shellcheck
steps:
- uses: actions/checkout@v3
- uses: ludeeus/action-shellcheck@master

actionlint-pr:
runs-on: ubuntu-latest
name: PR - Actionlint
steps:
- uses: actions/checkout@v3
- run: |
echo "::add-matcher::.github/actionlint-matcher.json"
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -color -shellcheck=
shell: bash
docslint-pr:
runs-on: ubuntu-latest
name: PR - Markdownlint
steps:
- name: Run markdownlint
uses: actionshub/[email protected]

golint-pr:
runs-on: ubuntu-latest
name: PR - GO lint
steps:
- uses: actions/checkout@v3

- name: golangci-lint
uses: reviewdog/action-golangci-lint@v2
19 changes: 12 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
FROM quay.io/prometheus/busybox:latest
FROM golang:1.19 AS build

ARG OS=linux
ARG ARCH=amd64
WORKDIR /

LABEL maintainer="Jorge Niedbalski <[email protected]>"
COPY . .

COPY .build/$OS-$ARCH/openstack-exporter /bin/openstack-exporter
RUN go mod download && go build -o /openstack-exporter .

ENTRYPOINT ["/bin/openstack-exporter"]
EXPOSE 9180
FROM busybox:stable-glibc as openstack-exporter

LABEL maintainer="Jorge Niedbalski <[email protected]>"

COPY --from=build /openstack-exporter /bin/openstack-exporter

ENTRYPOINT [ "/bin/openstack-exporter" ]
EXPOSE 9180
7 changes: 7 additions & 0 deletions exporters/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ func NewExporter(name, prefix, cloud string, disabledMetrics []string, endpointT
return nil, err
}
}
case "computeWithTeam":
{
exporter, err = NewNovaTeamExporter(&exporterConfig)
if err != nil {
return nil, err
}
}
case "image":
{
exporter, err = NewGlanceExporter(&exporterConfig)
Expand Down
78 changes: 78 additions & 0 deletions exporters/nova-with-team.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package exporters

import (
"fmt"

"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/availabilityzones"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
"github.com/prometheus/client_golang/prometheus"
)

var defaultNovaWithTeamMetrics = []Metric{
{Name: "flavors", Fn: ListFlavors},
{Name: "availability_zones", Fn: ListAZs},
{Name: "security_groups", Fn: ListComputeSecGroups},
{Name: "total_vms", Fn: NovaTeamListAllServers},
{Name: "agent_state", Labels: []string{"id", "hostname", "service", "adminState", "zone", "disabledReason"}, Fn: ListNovaAgentState},
{Name: "running_vms", Labels: []string{"hostname", "availability_zone", "aggregates"}, Fn: ListHypervisors},
{Name: "current_workload", Labels: []string{"hostname", "availability_zone", "aggregates"}},
{Name: "vcpus_available", Labels: []string{"hostname", "availability_zone", "aggregates"}},
{Name: "vcpus_used", Labels: []string{"hostname", "availability_zone", "aggregates"}},
{Name: "memory_available_bytes", Labels: []string{"hostname", "availability_zone", "aggregates"}},
{Name: "memory_used_bytes", Labels: []string{"hostname", "availability_zone", "aggregates"}},
{Name: "local_storage_available_bytes", Labels: []string{"hostname", "availability_zone", "aggregates"}},
{Name: "local_storage_used_bytes", Labels: []string{"hostname", "availability_zone", "aggregates"}},
{Name: "server_status", Labels: []string{"id", "status", "name", "tenant_id", "user_id", "address_ipv4",
"address_ipv6", "host_id", "uuid", "availability_zone", "flavor_id", "team"}},
{Name: "limits_vcpus_max", Labels: []string{"tenant", "tenant_id"}, Fn: ListComputeLimits},
{Name: "limits_vcpus_used", Labels: []string{"tenant", "tenant_id"}},
{Name: "limits_memory_max", Labels: []string{"tenant", "tenant_id"}},
{Name: "limits_memory_used", Labels: []string{"tenant", "tenant_id"}},
}

func NewNovaTeamExporter(config *ExporterConfig) (*NovaExporter, error) {
exporter := NovaExporter{
BaseOpenStackExporter{
Name: "nova",
ExporterConfig: *config,
},
}
for _, metric := range defaultNovaWithTeamMetrics {
exporter.AddMetric(metric.Name, metric.Fn, metric.Labels, nil)
}

return &exporter, nil
}

// NovaTeamListAllServers is copy of ListAllServers in nova.go + team label
func NovaTeamListAllServers(exporter *BaseOpenStackExporter, ch chan<- prometheus.Metric) error {
UpdateProjectIDTeamMap()
type ServerWithExt struct {
servers.Server
availabilityzones.ServerAvailabilityZoneExt
}

var allServers []ServerWithExt

allPagesServers, err := servers.List(exporter.Client, servers.ListOpts{AllTenants: true}).AllPages()
if err != nil {
return err
}

err = servers.ExtractServersInto(allPagesServers, &allServers)
if err != nil {
return err
}

ch <- prometheus.MustNewConstMetric(exporter.Metrics["total_vms"].Metric,
prometheus.GaugeValue, float64(len(allServers)))

// Server status metrics
for _, server := range allServers {
ch <- prometheus.MustNewConstMetric(exporter.Metrics["server_status"].Metric,
prometheus.GaugeValue, float64(mapServerStatus(server.Status)), server.ID, server.Status, server.Name, server.TenantID,
server.UserID, server.AccessIPv4, server.AccessIPv6, server.HostID, server.ID, server.AvailabilityZone, fmt.Sprintf("%v", server.Flavor["id"]), getTeam(server.TenantID))
}

return nil
}
125 changes: 125 additions & 0 deletions exporters/team.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package exporters

import (
"crypto/tls"
"net/http"
"strings"
"sync"

"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/identity/v3/projects"
"github.com/gophercloud/utils/openstack/clientconfig"
"github.com/prometheus/common/log"
)

// TeamSuffix is suffix of labels on tenenat e.g: test-team
const TeamSuffix = "-team"

var (
projectIDTeamMap = make(map[string]string)
projectIDTeamMapMutex sync.RWMutex
)

// getTeam retrieves the team name from projectIDTeamMap
func getTeam(tenantId string) string {
projectIDTeamMapMutex.RLock()
teamName := projectIDTeamMap[tenantId]
projectIDTeamMapMutex.RUnlock()
return teamName
}

// UpdateProjectIDTeamMap job is get and set tenant_id:teamName to projectIDTeamMap
func UpdateProjectIDTeamMap() {
log.Info("Updating ProjectID Team Map...")
extractTeamFromTags := func(tags []string) (tag string) {
for _, t := range tags {
if strings.HasSuffix(t, TeamSuffix) {
return t
}
}
return ""
}

allProjects, err := listAllProjects()
if err != nil {
log.Errorf("could not get projects: %s", err)
return
} else {

ProjectsWithTeamTag := getProjectsWithTeamTag(allProjects)

projectIDTeamMapMutex.Lock()
defer projectIDTeamMapMutex.Unlock()
for _, p := range ProjectsWithTeamTag {
projectIDTeamMap[p.ID] = extractTeamFromTags(p.Tags)
}
}
}

// getProjectsWithTeamTag get all projects and return list of project that has -team label
func getProjectsWithTeamTag(projs []projects.Project) []projects.Project {
var projectsWtihTeamTag []projects.Project

isTagsContainTeam := func(tags []string) bool {
for _, tag := range tags {
if strings.HasSuffix(tag, TeamSuffix) {
return true
}
}
return false
}

for _, p := range projs {
if isTagsContainTeam(p.Tags) {
projectsWtihTeamTag = append(projectsWtihTeamTag, p)
}
}
log.Info("ProjectID Team Map Updated.")
return projectsWtihTeamTag
}

// listAllProject return all projects that get from openstack.
func listAllProjects() ([]projects.Project, error) {

allPagesProject, err := projects.List(TeamServiceClient, projects.ListOpts{}).AllPages()
if err != nil {
log.Errorf("could not get projects: %s", err)
return nil, err
}

allProjects, err := projects.ExtractProjects(allPagesProject)
if err != nil {
log.Errorf("projects Extrcat failed: %s", err)
return nil, err
}
return allProjects, nil

}

var TeamServiceClient *gophercloud.ServiceClient

// NewTeamServiceClient creae and return a keystone client
func NewTeamServiceClient(cloud string, endpointType string) (*gophercloud.ServiceClient, error) {
clientName := "identity"
var err error
var transport *http.Transport

opts := clientconfig.ClientOpts{Cloud: cloud}

config, err := clientconfig.GetCloudFromYAML(&opts)
if err != nil {
return nil, err
}

if !*config.Verify {
log.Infoln("SSL verification disabled on transport")
tlsConfig := &tls.Config{InsecureSkipVerify: true}
transport = &http.Transport{TLSClientConfig: tlsConfig}
}

client, err := NewServiceClient(clientName, &opts, transport, endpointType)
if err != nil {
return nil, err
}
return client, nil
}
Loading

0 comments on commit d7cc2d3

Please sign in to comment.