provider/librato: Add Librato provider
This commit is contained in:
parent
3e06a75926
commit
8f07a2d6d5
|
@ -787,6 +787,10 @@
|
|||
"ImportPath": "github.com/hashicorp/yamux",
|
||||
"Rev": "df949784da9ed028ee76df44652e42d37a09d7e4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/henrikhodne/go-librato/librato",
|
||||
"Rev": "613abdebf4922c4d9d46bcb4bcf14ee18c08d7de"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hmrc/vmware-govcd",
|
||||
"Comment": "v0.0.2-37-g5cd82f0",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/builtin/providers/librato"
|
||||
"github.com/hashicorp/terraform/plugin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.Serve(&plugin.ServeOpts{
|
||||
ProviderFunc: librato.Provider,
|
||||
})
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package main
|
|
@ -0,0 +1,41 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/henrikhodne/go-librato/librato"
|
||||
)
|
||||
|
||||
// Provider returns a schema.Provider for Librato.
|
||||
func Provider() terraform.ResourceProvider {
|
||||
return &schema.Provider{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"email": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("LIBRATO_EMAIL", nil),
|
||||
Description: "The email address for the Librato account.",
|
||||
},
|
||||
|
||||
"token": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("LIBRATO_TOKEN", nil),
|
||||
Description: "The auth token for the Librato account.",
|
||||
},
|
||||
},
|
||||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"librato_space": resourceLibratoSpace(),
|
||||
"librato_space_chart": resourceLibratoSpaceChart(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
}
|
||||
}
|
||||
|
||||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
client := librato.NewClient(d.Get("email").(string), d.Get("token").(string))
|
||||
|
||||
return client, nil
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
var testAccProviders map[string]terraform.ResourceProvider
|
||||
var testAccProvider *schema.Provider
|
||||
|
||||
func init() {
|
||||
testAccProvider = Provider().(*schema.Provider)
|
||||
testAccProviders = map[string]terraform.ResourceProvider{
|
||||
"librato": testAccProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_impl(t *testing.T) {
|
||||
var _ terraform.ResourceProvider = Provider()
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
if v := os.Getenv("LIBRATO_EMAIL"); v == "" {
|
||||
t.Fatal("LIBRATO_EMAIL must be set for acceptance tests")
|
||||
}
|
||||
|
||||
if v := os.Getenv("LIBRATO_TOKEN"); v == "" {
|
||||
t.Fatal("LIBRATO_TOKEN must be set for acceptance tests")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/henrikhodne/go-librato/librato"
|
||||
)
|
||||
|
||||
func resourceLibratoSpace() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceLibratoSpaceCreate,
|
||||
Read: resourceLibratoSpaceRead,
|
||||
Update: resourceLibratoSpaceUpdate,
|
||||
Delete: resourceLibratoSpaceDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: false,
|
||||
},
|
||||
"id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
|
||||
name := d.Get("name").(string)
|
||||
|
||||
space, _, err := client.Spaces.Create(&librato.Space{Name: librato.String(name)})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Librato space %s: %s", name, err)
|
||||
}
|
||||
|
||||
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
_, _, err := client.Spaces.Get(*space.ID)
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
return resource.RetryableError(err)
|
||||
}
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return resourceLibratoSpaceReadResult(d, space)
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
|
||||
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
space, _, err := client.Spaces.Get(uint(id))
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading Librato Space %s: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
return resourceLibratoSpaceReadResult(d, space)
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceReadResult(d *schema.ResourceData, space *librato.Space) error {
|
||||
d.SetId(strconv.FormatUint(uint64(*space.ID), 10))
|
||||
if err := d.Set("id", *space.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Set("name", *space.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.HasChange("name") {
|
||||
newName := d.Get("name").(string)
|
||||
log.Printf("[INFO] Modifying name space attribute for %d: %#v", id, newName)
|
||||
if _, err = client.Spaces.Edit(uint(id), &librato.Space{Name: &newName}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return resourceLibratoSpaceRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Deleting Space: %d", id)
|
||||
_, err = client.Spaces.Delete(uint(id))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting space: %s", err)
|
||||
}
|
||||
|
||||
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
_, _, err := client.Spaces.Get(uint(id))
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
return nil
|
||||
}
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
return resource.RetryableError(fmt.Errorf("space still exists"))
|
||||
})
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,447 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/henrikhodne/go-librato/librato"
|
||||
)
|
||||
|
||||
func resourceLibratoSpaceChart() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceLibratoSpaceChartCreate,
|
||||
Read: resourceLibratoSpaceChartRead,
|
||||
Update: resourceLibratoSpaceChartUpdate,
|
||||
Delete: resourceLibratoSpaceChartDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"space_id": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"min": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Default: math.NaN(),
|
||||
Optional: true,
|
||||
},
|
||||
"max": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Default: math.NaN(),
|
||||
Optional: true,
|
||||
},
|
||||
"label": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"related_space": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
"stream": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"metric": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"stream.composite"},
|
||||
},
|
||||
"source": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"stream.composite"},
|
||||
},
|
||||
"group_function": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"stream.composite"},
|
||||
},
|
||||
"composite": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"stream.metric", "stream.source", "stream.group_function"},
|
||||
},
|
||||
"summary_function": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"color": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"units_short": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"units_long": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"min": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Default: math.NaN(),
|
||||
Optional: true,
|
||||
},
|
||||
"max": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Default: math.NaN(),
|
||||
Optional: true,
|
||||
},
|
||||
"transform_function": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"period": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Set: resourceLibratoSpaceChartHash,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceChartHash(v interface{}) int {
|
||||
var buf bytes.Buffer
|
||||
m := v.(map[string]interface{})
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["metric"].(string)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["source"].(string)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["composite"].(string)))
|
||||
|
||||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceChartCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
|
||||
spaceID := uint(d.Get("space_id").(int))
|
||||
|
||||
spaceChart := new(librato.SpaceChart)
|
||||
if v, ok := d.GetOk("name"); ok {
|
||||
spaceChart.Name = librato.String(v.(string))
|
||||
}
|
||||
if v, ok := d.GetOk("type"); ok {
|
||||
spaceChart.Type = librato.String(v.(string))
|
||||
}
|
||||
if v, ok := d.GetOk("min"); ok {
|
||||
if math.IsNaN(v.(float64)) {
|
||||
spaceChart.Min = nil
|
||||
} else {
|
||||
spaceChart.Min = librato.Float(v.(float64))
|
||||
}
|
||||
}
|
||||
if v, ok := d.GetOk("max"); ok {
|
||||
if math.IsNaN(v.(float64)) {
|
||||
spaceChart.Max = nil
|
||||
} else {
|
||||
spaceChart.Max = librato.Float(v.(float64))
|
||||
}
|
||||
}
|
||||
if v, ok := d.GetOk("label"); ok {
|
||||
spaceChart.Label = librato.String(v.(string))
|
||||
}
|
||||
if v, ok := d.GetOk("related_space"); ok {
|
||||
spaceChart.RelatedSpace = librato.Uint(uint(v.(int)))
|
||||
}
|
||||
if v, ok := d.GetOk("stream"); ok {
|
||||
vs := v.(*schema.Set)
|
||||
streams := make([]librato.SpaceChartStream, vs.Len())
|
||||
for i, streamDataM := range vs.List() {
|
||||
streamData := streamDataM.(map[string]interface{})
|
||||
var stream librato.SpaceChartStream
|
||||
if v, ok := streamData["metric"].(string); ok && v != "" {
|
||||
stream.Metric = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["source"].(string); ok && v != "" {
|
||||
stream.Source = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["composite"].(string); ok && v != "" {
|
||||
stream.Composite = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["group_function"].(string); ok && v != "" {
|
||||
stream.GroupFunction = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["summary_function"].(string); ok && v != "" {
|
||||
stream.SummaryFunction = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["transform_function"].(string); ok && v != "" {
|
||||
stream.TransformFunction = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["color"].(string); ok && v != "" {
|
||||
stream.Color = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["units_short"].(string); ok && v != "" {
|
||||
stream.UnitsShort = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["units_longs"].(string); ok && v != "" {
|
||||
stream.UnitsLong = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["min"].(float64); ok && !math.IsNaN(v) {
|
||||
stream.Min = librato.Float(v)
|
||||
}
|
||||
if v, ok := streamData["max"].(float64); ok && !math.IsNaN(v) {
|
||||
stream.Max = librato.Float(v)
|
||||
}
|
||||
streams[i] = stream
|
||||
}
|
||||
spaceChart.Streams = streams
|
||||
}
|
||||
|
||||
spaceChartResult, _, err := client.Spaces.CreateChart(spaceID, spaceChart)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Librato space chart %s: %s", *spaceChart.Name, err)
|
||||
}
|
||||
|
||||
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
_, _, err := client.Spaces.GetChart(spaceID, *spaceChartResult.ID)
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
return resource.RetryableError(err)
|
||||
}
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return resourceLibratoSpaceChartReadResult(d, spaceChartResult)
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceChartRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
|
||||
spaceID := uint(d.Get("space_id").(int))
|
||||
|
||||
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chart, _, err := client.Spaces.GetChart(spaceID, uint(id))
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error reading Librato Space chart %s: %s", d.Id(), err)
|
||||
}
|
||||
|
||||
return resourceLibratoSpaceChartReadResult(d, chart)
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceChartReadResult(d *schema.ResourceData, chart *librato.SpaceChart) error {
|
||||
d.SetId(strconv.FormatUint(uint64(*chart.ID), 10))
|
||||
if chart.Name != nil {
|
||||
if err := d.Set("name", *chart.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if chart.Type != nil {
|
||||
if err := d.Set("type", *chart.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if chart.Min != nil {
|
||||
if err := d.Set("min", *chart.Min); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if chart.Max != nil {
|
||||
if err := d.Set("max", *chart.Max); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if chart.Label != nil {
|
||||
if err := d.Set("label", *chart.Label); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if chart.RelatedSpace != nil {
|
||||
if err := d.Set("related_space", *chart.RelatedSpace); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
streams := resourceLibratoSpaceChartStreamsGather(d, chart.Streams)
|
||||
if err := d.Set("stream", streams); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceChartStreamsGather(d *schema.ResourceData, streams []librato.SpaceChartStream) []map[string]interface{} {
|
||||
retStreams := make([]map[string]interface{}, 0, len(streams))
|
||||
for _, s := range streams {
|
||||
stream := make(map[string]interface{})
|
||||
if s.Metric != nil {
|
||||
stream["metric"] = *s.Metric
|
||||
}
|
||||
if s.Source != nil {
|
||||
stream["source"] = *s.Source
|
||||
}
|
||||
if s.Composite != nil {
|
||||
stream["composite"] = *s.Composite
|
||||
}
|
||||
if s.GroupFunction != nil {
|
||||
stream["group_function"] = *s.GroupFunction
|
||||
}
|
||||
if s.SummaryFunction != nil {
|
||||
stream["summary_function"] = *s.SummaryFunction
|
||||
}
|
||||
if s.TransformFunction != nil {
|
||||
stream["transform_function"] = *s.TransformFunction
|
||||
}
|
||||
if s.Color != nil {
|
||||
stream["color"] = *s.Color
|
||||
}
|
||||
if s.UnitsShort != nil {
|
||||
stream["units_short"] = *s.UnitsShort
|
||||
}
|
||||
if s.UnitsLong != nil {
|
||||
stream["units_long"] = *s.UnitsLong
|
||||
}
|
||||
retStreams = append(retStreams, stream)
|
||||
}
|
||||
|
||||
return retStreams
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceChartUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
|
||||
spaceID := uint(d.Get("space_id").(int))
|
||||
chartID, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spaceChart := new(librato.SpaceChart)
|
||||
if d.HasChange("name") {
|
||||
spaceChart.Name = librato.String(d.Get("name").(string))
|
||||
}
|
||||
if d.HasChange("min") {
|
||||
if math.IsNaN(d.Get("min").(float64)) {
|
||||
spaceChart.Min = nil
|
||||
} else {
|
||||
spaceChart.Min = librato.Float(d.Get("min").(float64))
|
||||
}
|
||||
}
|
||||
if d.HasChange("max") {
|
||||
if math.IsNaN(d.Get("max").(float64)) {
|
||||
spaceChart.Max = nil
|
||||
} else {
|
||||
spaceChart.Max = librato.Float(d.Get("max").(float64))
|
||||
}
|
||||
}
|
||||
if d.HasChange("label") {
|
||||
spaceChart.Label = librato.String(d.Get("label").(string))
|
||||
}
|
||||
if d.HasChange("related_space") {
|
||||
spaceChart.RelatedSpace = librato.Uint(d.Get("related_space").(uint))
|
||||
}
|
||||
if d.HasChange("stream") {
|
||||
vs := d.Get("stream").(*schema.Set)
|
||||
streams := make([]librato.SpaceChartStream, vs.Len())
|
||||
for i, streamDataM := range vs.List() {
|
||||
streamData := streamDataM.(map[string]interface{})
|
||||
var stream librato.SpaceChartStream
|
||||
if v, ok := streamData["metric"].(string); ok && v != "" {
|
||||
stream.Metric = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["source"].(string); ok && v != "" {
|
||||
stream.Source = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["composite"].(string); ok && v != "" {
|
||||
stream.Composite = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["group_function"].(string); ok && v != "" {
|
||||
stream.GroupFunction = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["summary_function"].(string); ok && v != "" {
|
||||
stream.SummaryFunction = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["transform_function"].(string); ok && v != "" {
|
||||
stream.TransformFunction = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["color"].(string); ok && v != "" {
|
||||
stream.Color = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["units_short"].(string); ok && v != "" {
|
||||
stream.UnitsShort = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["units_longs"].(string); ok && v != "" {
|
||||
stream.UnitsLong = librato.String(v)
|
||||
}
|
||||
if v, ok := streamData["min"].(float64); ok && !math.IsNaN(v) {
|
||||
stream.Min = librato.Float(v)
|
||||
}
|
||||
if v, ok := streamData["max"].(float64); ok && !math.IsNaN(v) {
|
||||
stream.Max = librato.Float(v)
|
||||
}
|
||||
streams[i] = stream
|
||||
}
|
||||
spaceChart.Streams = streams
|
||||
}
|
||||
|
||||
_, err = client.Spaces.EditChart(spaceID, uint(chartID), spaceChart)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating Librato space chart %s: %s", *spaceChart.Name, err)
|
||||
}
|
||||
|
||||
return resourceLibratoSpaceChartRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceLibratoSpaceChartDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*librato.Client)
|
||||
|
||||
spaceID := uint(d.Get("space_id").(int))
|
||||
|
||||
id, err := strconv.ParseUint(d.Id(), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Deleting Chart: %d/%d", spaceID, uint(id))
|
||||
_, err = client.Spaces.DeleteChart(spaceID, uint(id))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting space: %s", err)
|
||||
}
|
||||
|
||||
resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||
_, _, err := client.Spaces.GetChart(spaceID, uint(id))
|
||||
if err != nil {
|
||||
if errResp, ok := err.(*librato.ErrorResponse); ok && errResp.Response.StatusCode == 404 {
|
||||
return nil
|
||||
}
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
return resource.RetryableError(fmt.Errorf("space chart still exists"))
|
||||
})
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/henrikhodne/go-librato/librato"
|
||||
)
|
||||
|
||||
func TestAccLibratoSpaceChart_Basic(t *testing.T) {
|
||||
var spaceChart librato.SpaceChart
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLibratoSpaceChartDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckLibratoSpaceChartConfig_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLibratoSpaceChartExists("librato_space_chart.foobar", &spaceChart),
|
||||
testAccCheckLibratoSpaceChartName(&spaceChart, "Foo Bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"librato_space_chart.foobar", "name", "Foo Bar"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccLibratoSpaceChart_Full(t *testing.T) {
|
||||
var spaceChart librato.SpaceChart
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLibratoSpaceChartDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckLibratoSpaceChartConfig_full,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLibratoSpaceChartExists("librato_space_chart.foobar", &spaceChart),
|
||||
testAccCheckLibratoSpaceChartName(&spaceChart, "Foo Bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"librato_space_chart.foobar", "name", "Foo Bar"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccLibratoSpaceChart_Updated(t *testing.T) {
|
||||
var spaceChart librato.SpaceChart
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLibratoSpaceChartDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckLibratoSpaceChartConfig_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLibratoSpaceChartExists("librato_space_chart.foobar", &spaceChart),
|
||||
testAccCheckLibratoSpaceChartName(&spaceChart, "Foo Bar"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"librato_space_chart.foobar", "name", "Foo Bar"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccCheckLibratoSpaceChartConfig_new_value,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLibratoSpaceChartExists("librato_space_chart.foobar", &spaceChart),
|
||||
testAccCheckLibratoSpaceChartName(&spaceChart, "Bar Baz"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"librato_space_chart.foobar", "name", "Bar Baz"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckLibratoSpaceChartDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*librato.Client)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "librato_space_chart" {
|
||||
continue
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ID not a number")
|
||||
}
|
||||
|
||||
spaceID, err := strconv.ParseUint(rs.Primary.Attributes["space_id"], 10, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Space ID not a number")
|
||||
}
|
||||
|
||||
_, _, err = client.Spaces.GetChart(uint(spaceID), uint(id))
|
||||
|
||||
if err == nil {
|
||||
return fmt.Errorf("Space Chart still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckLibratoSpaceChartName(spaceChart *librato.SpaceChart, name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
||||
if spaceChart.Name == nil || *spaceChart.Name != name {
|
||||
return fmt.Errorf("Bad name: %s", *spaceChart.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckLibratoSpaceChartExists(n string, spaceChart *librato.SpaceChart) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No Space Chart ID is set")
|
||||
}
|
||||
|
||||
client := testAccProvider.Meta().(*librato.Client)
|
||||
|
||||
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ID not a number")
|
||||
}
|
||||
|
||||
spaceID, err := strconv.ParseUint(rs.Primary.Attributes["space_id"], 10, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Space ID not a number")
|
||||
}
|
||||
|
||||
foundSpaceChart, _, err := client.Spaces.GetChart(uint(spaceID), uint(id))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if foundSpaceChart.ID == nil || *foundSpaceChart.ID != uint(id) {
|
||||
return fmt.Errorf("Space not found")
|
||||
}
|
||||
|
||||
*spaceChart = *foundSpaceChart
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckLibratoSpaceChartConfig_basic = `
|
||||
resource "librato_space" "foobar" {
|
||||
name = "Foo Bar"
|
||||
}
|
||||
|
||||
resource "librato_space_chart" "foobar" {
|
||||
space_id = "${librato_space.foobar.id}"
|
||||
name = "Foo Bar"
|
||||
type = "line"
|
||||
}`
|
||||
|
||||
const testAccCheckLibratoSpaceChartConfig_new_value = `
|
||||
resource "librato_space" "foobar" {
|
||||
name = "Foo Bar"
|
||||
}
|
||||
|
||||
resource "librato_space_chart" "foobar" {
|
||||
space_id = "${librato_space.foobar.id}"
|
||||
name = "Bar Baz"
|
||||
type = "line"
|
||||
}`
|
||||
|
||||
const testAccCheckLibratoSpaceChartConfig_full = `
|
||||
resource "librato_space" "foobar" {
|
||||
name = "Foo Bar"
|
||||
}
|
||||
|
||||
resource "librato_space" "barbaz" {
|
||||
name = "Bar Baz"
|
||||
}
|
||||
|
||||
resource "librato_space_chart" "foobar" {
|
||||
space_id = "${librato_space.foobar.id}"
|
||||
name = "Foo Bar"
|
||||
type = "line"
|
||||
min = 0
|
||||
max = 100
|
||||
label = "Percent"
|
||||
related_space = "${librato_space.barbaz.id}"
|
||||
|
||||
# Minimal metric stream
|
||||
stream {
|
||||
metric = "cpu"
|
||||
source = "*"
|
||||
}
|
||||
|
||||
# Minimal composite stream
|
||||
stream {
|
||||
composite = "s(\"cpu\", \"*\")"
|
||||
}
|
||||
|
||||
# Full metric stream
|
||||
stream {
|
||||
metric = "cpu"
|
||||
source = "*"
|
||||
group_function = "average"
|
||||
summary_function = "max"
|
||||
name = "CPU usage"
|
||||
color = "#990000"
|
||||
units_short = "%"
|
||||
units_long = "percent"
|
||||
min = 0
|
||||
max = 100
|
||||
transform_function = "x * 100"
|
||||
period = 60
|
||||
}
|
||||
}`
|
|
@ -0,0 +1,106 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/henrikhodne/go-librato/librato"
|
||||
)
|
||||
|
||||
func TestAccLibratoSpace_Basic(t *testing.T) {
|
||||
var space librato.Space
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckLibratoSpaceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccCheckLibratoSpaceConfig_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckLibratoSpaceExists("librato_space.foobar", &space),
|
||||
testAccCheckLibratoSpaceAttributes(&space),
|
||||
resource.TestCheckResourceAttr(
|
||||
"librato_space.foobar", "name", "Foo Bar"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckLibratoSpaceDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*librato.Client)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "librato_space" {
|
||||
continue
|
||||
}
|
||||
|
||||
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ID not a number")
|
||||
}
|
||||
|
||||
_, _, err = client.Spaces.Get(uint(id))
|
||||
|
||||
if err == nil {
|
||||
return fmt.Errorf("Space still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckLibratoSpaceAttributes(space *librato.Space) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
||||
if space.Name == nil || *space.Name != "Foo Bar" {
|
||||
return fmt.Errorf("Bad name: %s", *space.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckLibratoSpaceExists(n string, space *librato.Space) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No Space ID is set")
|
||||
}
|
||||
|
||||
client := testAccProvider.Meta().(*librato.Client)
|
||||
|
||||
id, err := strconv.ParseUint(rs.Primary.ID, 10, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ID not a number")
|
||||
}
|
||||
|
||||
foundSpace, _, err := client.Spaces.Get(uint(id))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if foundSpace.ID == nil || *foundSpace.ID != uint(id) {
|
||||
return fmt.Errorf("Space not found")
|
||||
}
|
||||
|
||||
*space = *foundSpace
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckLibratoSpaceConfig_basic = `
|
||||
resource "librato_space" "foobar" {
|
||||
name = "Foo Bar"
|
||||
}`
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright 2015 Henrik Hodne
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,282 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
const (
|
||||
libraryVersion = "0.1"
|
||||
defaultBaseURL = "https://metrics-api.librato.com/v1/"
|
||||
userAgent = "go-librato/" + libraryVersion
|
||||
|
||||
defaultMediaType = "application/json"
|
||||
)
|
||||
|
||||
// A Client manages communication with the Librato API.
|
||||
type Client struct {
|
||||
// HTTP client used to communicate with the API
|
||||
client *http.Client
|
||||
|
||||
// Headers to attach to every request made with the client. Headers will be
|
||||
// used to provide Librato API authentication details and other necessary
|
||||
// headers.
|
||||
Headers map[string]string
|
||||
|
||||
// Email and Token contains the authentication details needed to authenticate
|
||||
// against the Librato API.
|
||||
Email, Token string
|
||||
|
||||
// Base URL for API requests. Defaults to the public Librato API, but can be
|
||||
// set to an alternate endpoint if necessary. BaseURL should always be
|
||||
// terminated by a slash.
|
||||
BaseURL *url.URL
|
||||
|
||||
// User agent used when communicating with the Librato API.
|
||||
UserAgent string
|
||||
|
||||
// Services used to manipulate API entities.
|
||||
Spaces *SpacesService
|
||||
}
|
||||
|
||||
// NewClient returns a new Librato API client bound to the public Librato API.
|
||||
func NewClient(email, token string) *Client {
|
||||
bu, err := url.Parse(defaultBaseURL)
|
||||
if err != nil {
|
||||
panic("Default Librato API base URL couldn't be parsed")
|
||||
}
|
||||
|
||||
return NewClientWithBaseURL(bu, email, token)
|
||||
}
|
||||
|
||||
// NewClientWithBaseURL returned a new Librato API client with a custom base URL.
|
||||
func NewClientWithBaseURL(baseURL *url.URL, email, token string) *Client {
|
||||
headers := map[string]string{
|
||||
"Content-Type": defaultMediaType,
|
||||
"Accept": defaultMediaType,
|
||||
}
|
||||
|
||||
c := &Client{
|
||||
client: http.DefaultClient,
|
||||
Headers: headers,
|
||||
Email: email,
|
||||
Token: token,
|
||||
BaseURL: baseURL,
|
||||
UserAgent: userAgent,
|
||||
}
|
||||
|
||||
c.Spaces = &SpacesService{client: c}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// NewRequest creates an API request. A relative URL can be provided in urlStr,
|
||||
// in which case it is resolved relative to the BaseURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash. If
|
||||
// specified, the value pointed to by body is JSON encoded and included as the
|
||||
// request body. If specified, the map provided by headers will be used to
|
||||
// update request headers.
|
||||
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
|
||||
rel, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u := c.BaseURL.ResolveReference(rel)
|
||||
|
||||
var buf io.ReadWriter
|
||||
if body != nil {
|
||||
buf = new(bytes.Buffer)
|
||||
err := json.NewEncoder(buf).Encode(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, u.String(), buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.SetBasicAuth(c.Email, c.Token)
|
||||
if c.UserAgent != "" {
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
}
|
||||
|
||||
for k, v := range c.Headers {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Do sends an API request and returns the API response. The API response is
|
||||
// JSON decoded and stored in the value pointed to by v, or returned as an
|
||||
// error if an API error has occurred. If v implements the io.Writer
|
||||
// interface, the raw response body will be written to v, without attempting to
|
||||
// first decode it.
|
||||
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = CheckResponse(resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if v != nil {
|
||||
if w, ok := v.(io.Writer); ok {
|
||||
_, err = io.Copy(w, resp.Body)
|
||||
} else {
|
||||
err = json.NewDecoder(resp.Body).Decode(v)
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// ErrorResponse reports an error caused by an API request.
|
||||
// ErrorResponse implements the Error interface.
|
||||
type ErrorResponse struct {
|
||||
// HTTP response that caused this error
|
||||
Response *http.Response
|
||||
|
||||
// Error messages produces by Librato API.
|
||||
Errors ErrorResponseMessages `json:"errors"`
|
||||
}
|
||||
|
||||
func (er *ErrorResponse) Error() string {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if er.Errors.Params != nil && len(er.Errors.Params) > 0 {
|
||||
buf.WriteString(" Parameter errors:")
|
||||
for param, errs := range er.Errors.Params {
|
||||
fmt.Fprintf(buf, " %s:", param)
|
||||
for _, err := range errs {
|
||||
fmt.Fprintf(buf, " %s,", err)
|
||||
}
|
||||
}
|
||||
buf.WriteString(".")
|
||||
}
|
||||
|
||||
if er.Errors.Request != nil && len(er.Errors.Request) > 0 {
|
||||
buf.WriteString(" Request errors:")
|
||||
for _, err := range er.Errors.Request {
|
||||
fmt.Fprintf(buf, " %s,", err)
|
||||
}
|
||||
buf.WriteString(".")
|
||||
}
|
||||
|
||||
if er.Errors.System != nil && len(er.Errors.System) > 0 {
|
||||
buf.WriteString(" System errors:")
|
||||
for _, err := range er.Errors.System {
|
||||
fmt.Fprintf(buf, " %s,", err)
|
||||
}
|
||||
buf.WriteString(".")
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%v %v: %d %v",
|
||||
er.Response.Request.Method,
|
||||
er.Response.Request.URL,
|
||||
er.Response.StatusCode,
|
||||
buf.String(),
|
||||
)
|
||||
}
|
||||
|
||||
// ErrorResponseMessages contains error messages returned from the Librato API.
|
||||
type ErrorResponseMessages struct {
|
||||
Params map[string][]string `json:"params,omitempty"`
|
||||
Request []string `json:"request,omitempty"`
|
||||
System []string `json:"system,omitempty"`
|
||||
}
|
||||
|
||||
// CheckResponse checks the API response for errors; and returns them if
|
||||
// present. A Response is considered an error if it has a status code outside
|
||||
// the 2XX range.
|
||||
func CheckResponse(r *http.Response) error {
|
||||
if c := r.StatusCode; 200 <= c && c <= 299 {
|
||||
return nil
|
||||
}
|
||||
|
||||
errorResponse := &ErrorResponse{Response: r}
|
||||
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err == nil && data != nil {
|
||||
json.Unmarshal(data, errorResponse)
|
||||
}
|
||||
|
||||
return errorResponse
|
||||
}
|
||||
|
||||
func urlWithOptions(s string, opt interface{}) (string, error) {
|
||||
rv := reflect.ValueOf(opt)
|
||||
if rv.Kind() == reflect.Ptr && rv.IsNil() {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
qs, err := query.Values(opt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u.RawQuery = qs.Encode()
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// Bool is a helper routine that allocates a new bool value
|
||||
// to store v and returns a pointer to it.
|
||||
func Bool(v bool) *bool {
|
||||
p := new(bool)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// Int is a helper routine that allocates a new int32 value
|
||||
// to store v and returns a pointer to it, but unlike Int32
|
||||
// its argument value is an int.
|
||||
func Int(v int) *int {
|
||||
p := new(int)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// Uint is a helper routine that allocates a new uint value
|
||||
// to store v and returns a pointer to it.
|
||||
func Uint(v uint) *uint {
|
||||
p := new(uint)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// String is a helper routine that allocates a new string value
|
||||
// to store v and returns a pointer to it.
|
||||
func String(v string) *string {
|
||||
p := new(string)
|
||||
*p = v
|
||||
return p
|
||||
}
|
||||
|
||||
// Float is a helper routine that allocates a new float64 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Float(v float64) *float64 {
|
||||
p := new(float64)
|
||||
*p = v
|
||||
return p
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// SpacesService handles communication with the Librato API methods related to
|
||||
// spaces.
|
||||
type SpacesService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Space represents a Librato Space.
|
||||
type Space struct {
|
||||
Name *string `json:"name"`
|
||||
ID *uint `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (s Space) String() string {
|
||||
return Stringify(s)
|
||||
}
|
||||
|
||||
// SpaceListOptions specifies the optional parameters to the SpaceService.Find
|
||||
// method.
|
||||
type SpaceListOptions struct {
|
||||
// filter by name
|
||||
Name string `url:"name,omitempty"`
|
||||
}
|
||||
|
||||
type listSpacesResponse struct {
|
||||
Spaces []Space `json:"spaces"`
|
||||
}
|
||||
|
||||
// List spaces using the provided options.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/get/spaces
|
||||
func (s *SpacesService) List(opt *SpaceListOptions) ([]Space, *http.Response, error) {
|
||||
u, err := urlWithOptions("spaces", opt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var spacesResp listSpacesResponse
|
||||
resp, err := s.client.Do(req, &spacesResp)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return spacesResp.Spaces, resp, nil
|
||||
}
|
||||
|
||||
// Get fetches a space based on the provided ID.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/get/spaces/:id
|
||||
func (s *SpacesService) Get(id uint) (*Space, *http.Response, error) {
|
||||
u, err := urlWithOptions(fmt.Sprintf("spaces/%d", id), nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sp := new(Space)
|
||||
resp, err := s.client.Do(req, sp)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return sp, resp, err
|
||||
}
|
||||
|
||||
// Create a space with a given name.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/post/spaces
|
||||
func (s *SpacesService) Create(space *Space) (*Space, *http.Response, error) {
|
||||
req, err := s.client.NewRequest("POST", "spaces", space)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sp := new(Space)
|
||||
resp, err := s.client.Do(req, sp)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return sp, resp, err
|
||||
}
|
||||
|
||||
// Edit a space.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/put/spaces/:id
|
||||
func (s *SpacesService) Edit(spaceID uint, space *Space) (*http.Response, error) {
|
||||
u := fmt.Sprintf("spaces/%d", spaceID)
|
||||
req, err := s.client.NewRequest("PUT", u, space)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
|
||||
// Delete a space.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/delete/spaces/:id
|
||||
func (s *SpacesService) Delete(id uint) (*http.Response, error) {
|
||||
u := fmt.Sprintf("spaces/%d", id)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
118
vendor/github.com/henrikhodne/go-librato/librato/spaces_charts.go
generated
vendored
Normal file
118
vendor/github.com/henrikhodne/go-librato/librato/spaces_charts.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// SpaceChart represents a chart in a Librato Space.
|
||||
type SpaceChart struct {
|
||||
ID *uint `json:"id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Min *float64 `json:"min,omitempty"`
|
||||
Max *float64 `json:"max,omitempty"`
|
||||
Label *string `json:"label,omitempty"`
|
||||
RelatedSpace *uint `json:"related_space,omitempty"`
|
||||
Streams []SpaceChartStream `json:"streams,omitempty"`
|
||||
}
|
||||
|
||||
// SpaceChartStream represents a single stream in a chart in a Librato Space.
|
||||
type SpaceChartStream struct {
|
||||
Metric *string `json:"metric,omitempty"`
|
||||
Source *string `json:"source,omitempty"`
|
||||
Composite *string `json:"composite,omitempty"`
|
||||
GroupFunction *string `json:"group_function,omitempty"`
|
||||
SummaryFunction *string `json:"summary_function,omitempty"`
|
||||
Color *string `json:"color,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
UnitsShort *string `json:"units_short,omitempty"`
|
||||
UnitsLong *string `json:"units_long,omitempty"`
|
||||
Min *float64 `json:"min,omitempty"`
|
||||
Max *float64 `json:"max,omitempty"`
|
||||
TransformFunction *string `json:"transform_function,omitempty"`
|
||||
Period *int64 `json:"period,omitempty"`
|
||||
}
|
||||
|
||||
// CreateChart creates a chart in a given Librato Space.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/post/spaces/:id/charts
|
||||
func (s *SpacesService) CreateChart(spaceID uint, chart *SpaceChart) (*SpaceChart, *http.Response, error) {
|
||||
u := fmt.Sprintf("spaces/%d/charts", spaceID)
|
||||
req, err := s.client.NewRequest("POST", u, chart)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
c := new(SpaceChart)
|
||||
resp, err := s.client.Do(req, c)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return c, resp, err
|
||||
}
|
||||
|
||||
// ListCharts lists all charts in a given Librato Space.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/get/spaces/:id/charts
|
||||
func (s *SpacesService) ListCharts(spaceID uint) ([]SpaceChart, *http.Response, error) {
|
||||
u := fmt.Sprintf("spaces/%d/charts", spaceID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
charts := new([]SpaceChart)
|
||||
resp, err := s.client.Do(req, charts)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return *charts, resp, err
|
||||
}
|
||||
|
||||
// GetChart gets a chart with a given ID in a space with a given ID.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/get/spaces/:id/charts
|
||||
func (s *SpacesService) GetChart(spaceID, chartID uint) (*SpaceChart, *http.Response, error) {
|
||||
u := fmt.Sprintf("spaces/%d/charts/%d", spaceID, chartID)
|
||||
req, err := s.client.NewRequest("GET", u, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
c := new(SpaceChart)
|
||||
resp, err := s.client.Do(req, c)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
return c, resp, err
|
||||
}
|
||||
|
||||
// EditChart edits a chart.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/put/spaces/:id/charts/:id
|
||||
func (s *SpacesService) EditChart(spaceID, chartID uint, chart *SpaceChart) (*http.Response, error) {
|
||||
u := fmt.Sprintf("spaces/%d/charts/%d", spaceID, chartID)
|
||||
req, err := s.client.NewRequest("PUT", u, chart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
||||
|
||||
// DeleteChart deletes a chart.
|
||||
//
|
||||
// Librato API docs: http://dev.librato.com/v1/delete/spaces/:id/charts/:id
|
||||
func (s *SpacesService) DeleteChart(spaceID, chartID uint) (*http.Response, error) {
|
||||
u := fmt.Sprintf("spaces/%d/charts/%d", spaceID, chartID)
|
||||
req, err := s.client.NewRequest("DELETE", u, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.client.Do(req, nil)
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Stringify attempts to create a reasonable string representation of types in
|
||||
// the Librato library. It does things like resolve pointers to their values
|
||||
// and omits struct fields with nil values.
|
||||
func Stringify(message interface{}) string {
|
||||
var buf bytes.Buffer
|
||||
v := reflect.ValueOf(message)
|
||||
stringifyValue(&buf, v)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// stringifyValue was heavily inspired by the goprotobuf library.
|
||||
|
||||
func stringifyValue(w io.Writer, val reflect.Value) {
|
||||
if val.Kind() == reflect.Ptr && val.IsNil() {
|
||||
w.Write([]byte("<nil>"))
|
||||
return
|
||||
}
|
||||
|
||||
v := reflect.Indirect(val)
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
fmt.Fprintf(w, `"%s"`, v)
|
||||
case reflect.Slice:
|
||||
w.Write([]byte{'['})
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if i > 0 {
|
||||
w.Write([]byte{' '})
|
||||
}
|
||||
|
||||
stringifyValue(w, v.Index(i))
|
||||
}
|
||||
|
||||
w.Write([]byte{']'})
|
||||
return
|
||||
case reflect.Struct:
|
||||
if v.Type().Name() != "" {
|
||||
w.Write([]byte(v.Type().String()))
|
||||
}
|
||||
|
||||
w.Write([]byte{'{'})
|
||||
|
||||
var sep bool
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
fv := v.Field(i)
|
||||
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
||||
continue
|
||||
}
|
||||
if fv.Kind() == reflect.Slice && fv.IsNil() {
|
||||
continue
|
||||
}
|
||||
|
||||
if sep {
|
||||
w.Write([]byte(", "))
|
||||
} else {
|
||||
sep = true
|
||||
}
|
||||
|
||||
w.Write([]byte(v.Type().Field(i).Name))
|
||||
w.Write([]byte{':'})
|
||||
stringifyValue(w, fv)
|
||||
}
|
||||
|
||||
w.Write([]byte{'}'})
|
||||
default:
|
||||
if v.CanInterface() {
|
||||
fmt.Fprint(w, v.Interface())
|
||||
}
|
||||
}
|
||||
}
|
17
vendor/github.com/henrikhodne/go-librato/librato/testing_helpers.go
generated
vendored
Normal file
17
vendor/github.com/henrikhodne/go-librato/librato/testing_helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
package librato
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ok fails the test if an err is not nil.
|
||||
func ok(tb testing.TB, err error) {
|
||||
if err != nil {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
|
||||
tb.FailNow()
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ body.layout-fastly,
|
|||
body.layout-google,
|
||||
body.layout-heroku,
|
||||
body.layout-influxdb,
|
||||
body.layout-librato,
|
||||
body.layout-mailgun,
|
||||
body.layout-mysql,
|
||||
body.layout-openstack,
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
layout: "librato"
|
||||
page_title: "Provider: Librato"
|
||||
sidebar_current: "docs-librato-index"
|
||||
description: |-
|
||||
The Librato provider is used to interact with the resources supported by Librato. The provider needs to be configured with the proper credentials before it can be used.
|
||||
---
|
||||
|
||||
# Librato Provider
|
||||
|
||||
The Librato provider is used to interact with the
|
||||
resources supported by Librato. The provider needs to be configured
|
||||
with the proper credentials before it can be used.
|
||||
|
||||
Use the navigation to the left to read about the available resources.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
# Configure the Librato provider
|
||||
provider "librato" {
|
||||
email = "ops@company.com"
|
||||
token = "${var.librato_token}"
|
||||
}
|
||||
|
||||
# Create a new space
|
||||
resource "librato_space" "default" {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `token` - (Required) Librato API token. It must be provided, but it can also
|
||||
be sourced from the `LIBRATO_TOKEN` environment variable.
|
||||
* `email` - (Required) Librato email address. It must be provided, but it can
|
||||
also be sourced from the `LIBRATO_EMAIL` environment variable.
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
layout: "librato"
|
||||
page_title: "Librato: librato_space"
|
||||
sidebar_current: "docs-librato-resource-space"
|
||||
description: |-
|
||||
Provides a Librato Space resource. This can be used to create and manage spaces on Librato.
|
||||
---
|
||||
|
||||
# librato\_space
|
||||
|
||||
Provides a Librato Space resource. This can be used to
|
||||
create and manage spaces on Librato.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
# Create a new Librato space
|
||||
resource "librato_space" "default" {
|
||||
name = "My New Space"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The name of the space.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The ID of the space.
|
||||
* `name` - The name of the space.
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
layout: "librato"
|
||||
page_title: "Librato: librato_space_chart"
|
||||
sidebar_current: "docs-librato-resource-space-chart"
|
||||
description: |-
|
||||
Provides a Librato Space Chart resource. This can be used to create and manage charts in Librato Spaces.
|
||||
---
|
||||
|
||||
# librato\_space\_chart
|
||||
|
||||
Provides a Librato Space Chart resource. This can be used to
|
||||
create and manage charts in Librato Spaces.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
# Create a new Librato space
|
||||
resource "librato_space" "my_space" {
|
||||
name = "My New Space"
|
||||
}
|
||||
|
||||
# Create a new chart
|
||||
resource "librato_space_chart" "server_temperature" {
|
||||
name = "Server Temperature"
|
||||
space_id = "${librato_space.my_space.id}"
|
||||
|
||||
stream {
|
||||
metric = "server_temp"
|
||||
source = "app1"
|
||||
}
|
||||
|
||||
stream {
|
||||
metric = "environmental_temp"
|
||||
source = "*"
|
||||
group_function = "breakout"
|
||||
summary_function = "average"
|
||||
}
|
||||
|
||||
stream {
|
||||
metric = "server_temp"
|
||||
source = "%"
|
||||
group_function = "average"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `space_id` - (Required) The ID of the space this chart should be in.
|
||||
* `name` - (Required) The title of the chart when it is displayed.
|
||||
* `type` - (Optional) Indicates the type of chart. Must be one of line or
|
||||
stacked (default to line).
|
||||
* `min` - (Optional) The minimum display value of the chart's Y-axis.
|
||||
* `max` - (Optional) The maximum display value of the chart's Y-axis.
|
||||
* `label` - (Optional) The Y-axis label.
|
||||
* `related_space` - (Optional) The ID of another space to which this chart is
|
||||
related.
|
||||
* `stream` - (Optional) Nested block describing a metric to use for data in the
|
||||
chart. The structure of this block is described below.
|
||||
|
||||
The `stream` block supports:
|
||||
|
||||
* `metric` - (Required) The name of the metric. May not be specified if
|
||||
`composite` is specified.
|
||||
* `source` - (Required) The name of a source, or `*` to include all sources.
|
||||
This field will also accept specific wildcard entries. For example
|
||||
us-west-\*-app will match us-west-21-app but not us-west-12-db. Use % to
|
||||
specify a dynamic source that will be provided after the instrument or
|
||||
dashboard has loaded, or in the URL. May not be specified if `composite` is
|
||||
specified.
|
||||
* `group_function` - (Required) How to process the results when multiple sources
|
||||
will be returned. Value must be one of average, sum, breakout. If average or
|
||||
sum, a single line will be drawn representing the average or sum
|
||||
(respectively) of all sources. If the group_function is breakout, a separate
|
||||
line will be drawn for each source. If this property is not supplied, the
|
||||
behavior will default to average. May not be specified if `composite` is
|
||||
specified.
|
||||
* `composite` - (Required) A composite metric query string to execute when this
|
||||
stream is displayed. May not be specified if `metric`, `source` or
|
||||
`group_function` is specified.
|
||||
* `summary_function` - (Optional) When visualizing complex measurements or a
|
||||
rolled-up measurement, this allows you to choose which statistic to use.
|
||||
Defaults to "average". Valid options are: "max", "min", "average", "sum" or
|
||||
"count".
|
||||
* `name` - (Optional) A display name to use for the stream when generating the
|
||||
tooltip.
|
||||
* `color` - (Optional) Sets a color to use when rendering the stream. Must be a
|
||||
seven character string that represents the hex code of the color e.g.
|
||||
"#52D74C".
|
||||
* `units_short` - (Optional) Unit value string to use as the tooltip label.
|
||||
* `units_long` - (Optional) String value to set as they Y-axis label. All
|
||||
streams that share the same units_long value will be plotted on the same
|
||||
Y-axis.
|
||||
* `min` - (Optional) Theoretical minimum Y-axis value.
|
||||
* `max` - (Optional) Theoretical maximum Y-axis value.
|
||||
* `transform_function` - (Optional) Linear formula to run on each measurement
|
||||
prior to visualizaton.
|
||||
* `period` - (Optional) An integer value of seconds that defines the period this
|
||||
stream reports at. This aids in the display of the stream and allows the
|
||||
period to be used in stream display transforms.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The ID of the chart.
|
||||
* `space_id` - The ID of the space this chart should be in.
|
||||
* `title` - The title of the chart when it is displayed.
|
|
@ -215,6 +215,10 @@
|
|||
|
||||
<li<%= sidebar_current("docs-providers-influxdb") %>>
|
||||
<a href="/docs/providers/influxdb/index.html">InfluxDB</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-providers-librato") %>>
|
||||
<a href="/docs/providers/librato/index.html">Librato</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-providers-mailgun") %>>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<% wrap_layout :inner do %>
|
||||
<% content_for :sidebar do %>
|
||||
<div class="docs-sidebar hidden-print affix-top" role="complementary">
|
||||
<ul class="nav docs-sidenav">
|
||||
<li<%= sidebar_current("docs-home") %>>
|
||||
<a href="/docs/providers/index.html">« Documentation Home</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-librato-index") %>>
|
||||
<a href="/docs/providers/librato/index.html">Librato Provider</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current(/^docs-librato-resource/) %>>
|
||||
<a href="#">Resources</a>
|
||||
<ul class="nav nav-visible">
|
||||
<li<%= sidebar_current("docs-librato-resource-space") %>>
|
||||
<a href="/docs/providers/librato/r/space.html">librato_space</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-librato-resource-space-chart") %>>
|
||||
<a href="/docs/providers/librato/r/space_chart.html">librato_space_chart</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= yield %>
|
||||
<% end %>
|
Loading…
Reference in New Issue