
This patch will publish output if Rally fails to create the deployment for some reason. Change-Id: Ie5b4db653d7ffc43832abb5b376a0d67612f2665
181 lines
4.2 KiB
Go
181 lines
4.2 KiB
Go
package rally
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"time"
|
|
|
|
"github.com/gophercloud/utils/openstack/clientconfig"
|
|
"github.com/jinzhu/gorm"
|
|
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/common/log"
|
|
|
|
"opendev.org/vexxhost/rally-exporter/models"
|
|
)
|
|
|
|
// TaskLabels has the common labels used by every task.
|
|
var TaskLabels = []string{"title"}
|
|
|
|
// PeriodicRunner defines the structure of the collector
|
|
type PeriodicRunner struct {
|
|
prometheus.Collector
|
|
|
|
CloudName string
|
|
TaskFile string
|
|
|
|
TaskDuration *prometheus.Desc
|
|
TaskSLADesc *prometheus.Desc
|
|
TaskTime *prometheus.Desc
|
|
}
|
|
|
|
// NewPeriodicRunner creates a rally runner which executes every 5 minutes
|
|
func NewPeriodicRunner(cloudName string, taskFile string) *PeriodicRunner {
|
|
return &PeriodicRunner{
|
|
CloudName: cloudName,
|
|
TaskFile: taskFile,
|
|
TaskDuration: prometheus.NewDesc(
|
|
"rally_task_duration",
|
|
"Rally task duration",
|
|
TaskLabels, nil,
|
|
),
|
|
TaskSLADesc: prometheus.NewDesc(
|
|
"rally_task_passed",
|
|
"Rally task passed",
|
|
TaskLabels, nil,
|
|
),
|
|
TaskTime: prometheus.NewDesc(
|
|
"rally_task_time",
|
|
"Rally last run time",
|
|
[]string{}, nil,
|
|
),
|
|
}
|
|
}
|
|
|
|
// Run starts the PeriodicRunner which runs Rally every 5 minutes.
|
|
func (runner *PeriodicRunner) Run() {
|
|
runner.createDeployment()
|
|
|
|
for {
|
|
log.Info("Starting Rally run...")
|
|
cmd := exec.Command("rally", "task", "start", runner.TaskFile)
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
log.Error("Failed test, output below:")
|
|
} else {
|
|
log.Info("Successful run, output below:")
|
|
}
|
|
fmt.Println(string(output))
|
|
|
|
time.Sleep(5 * time.Minute)
|
|
}
|
|
}
|
|
|
|
func (runner *PeriodicRunner) createDeployment() {
|
|
opts := &clientconfig.ClientOpts{Cloud: runner.CloudName}
|
|
cloud, err := clientconfig.GetCloudFromYAML(opts)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
deployment := &Deployment{
|
|
OpenStackDeployment: OpenStackDeployment{
|
|
AuthURL: cloud.AuthInfo.AuthURL,
|
|
RegionName: cloud.RegionName,
|
|
EndpointType: cloud.EndpointType,
|
|
Users: []OpenStackUser{
|
|
OpenStackUser{
|
|
Username: cloud.AuthInfo.Username,
|
|
Password: cloud.AuthInfo.Password,
|
|
UserDomainName: cloud.AuthInfo.UserDomainName,
|
|
ProjectName: cloud.AuthInfo.ProjectName,
|
|
ProjectDomainName: cloud.AuthInfo.ProjectDomainName,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
b, err := json.Marshal(deployment)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
file, err := ioutil.TempFile("/tmp", "deployment")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer os.Remove(file.Name())
|
|
_, err = file.Write(b)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
cmd := exec.Command("rally", "deployment", "create", "--filename", file.Name(), "--name", runner.CloudName)
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
fmt.Println(string(output))
|
|
log.Fatal("Failed to install Rally deployment: ", err)
|
|
}
|
|
}
|
|
|
|
// Describe provides all the descriptions of all the information for the collector
|
|
func (runner *PeriodicRunner) Describe(ch chan<- *prometheus.Desc) {
|
|
ch <- runner.TaskDuration
|
|
ch <- runner.TaskSLADesc
|
|
ch <- runner.TaskTime
|
|
}
|
|
|
|
func getLatestTask(db *gorm.DB) (*models.Task, error) {
|
|
task := &models.Task{}
|
|
err := db.Not("status", []string{"running"}).Last(task).Error
|
|
|
|
return task, err
|
|
}
|
|
|
|
// Collect grabs all the data from the Rally database
|
|
func (runner *PeriodicRunner) Collect(ch chan<- prometheus.Metric) {
|
|
db, err := gorm.Open("sqlite3", "/home/rally/data/rally.db")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer db.Close()
|
|
|
|
task, err := getLatestTask(db)
|
|
if err != nil {
|
|
log.Error(err)
|
|
return
|
|
}
|
|
|
|
subtasks := []models.Subtask{}
|
|
if err := db.Where(&models.Subtask{TaskUUID: task.UUID}).Find(&subtasks).Error; err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
for _, subtask := range subtasks {
|
|
ch <- prometheus.MustNewConstMetric(
|
|
runner.TaskDuration,
|
|
prometheus.GaugeValue,
|
|
subtask.Duration, subtask.Title,
|
|
)
|
|
|
|
passSLA := float64(0)
|
|
if subtask.PassSLA && subtask.Status == "finished" {
|
|
passSLA = float64(1)
|
|
}
|
|
ch <- prometheus.MustNewConstMetric(
|
|
runner.TaskSLADesc,
|
|
prometheus.GaugeValue,
|
|
passSLA, subtask.Title,
|
|
)
|
|
}
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
runner.TaskTime,
|
|
prometheus.GaugeValue,
|
|
float64(task.UpdatedAt.Unix()),
|
|
)
|
|
}
|