Skip to content
This repository has been archived by the owner on Jan 15, 2024. It is now read-only.

Commit

Permalink
Add functionality to manage plugins (#68)
Browse files Browse the repository at this point in the history
* Add functionality to manage plugins

* Prefix plugin management with cloud

* Use stack slug instead of ID

* return ID of the installation

* Return CloudInstallation
  • Loading branch information
matthewnolf authored Mar 10, 2022
1 parent b2e5a8c commit 075eeb6
Show file tree
Hide file tree
Showing 2 changed files with 342 additions and 0 deletions.
125 changes: 125 additions & 0 deletions cloud_plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package gapi

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)

type Plugin struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Version string `json:"version"`
Description string `json:"description"`
}

type CloudPluginInstallation struct {
ID int `json:"id"`
InstanceID int `json:"instanceId"`
InstanceURL string `json:"instanceUrl"`
InstanceSlug string `json:"instanceSlug"`
PluginID int `json:"pluginId"`
PluginSlug string `json:"pluginSlug"`
PluginName string `json:"pluginName"`
Version string `json:"version"`
}

// InstallCloudPlugin installs the specified plugin to the given stack.
func (c *Client) InstallCloudPlugin(stackSlug string, pluginSlug string, pluginVersion string) (*CloudPluginInstallation, error) {
installPluginRequest := struct {
Plugin string `json:"plugin"`
Version string `json:"version"`
}{
Plugin: pluginSlug,
Version: pluginVersion,
}

data, err := json.Marshal(installPluginRequest)
if err != nil {
return nil, err
}

var installation CloudPluginInstallation

err = c.request("POST", fmt.Sprintf("/api/instances/%s/plugins", stackSlug), nil, bytes.NewBuffer(data), &installation)
if err != nil {
return nil, err
}

return &installation, nil
}

// UninstallCloudPlugin uninstalls the specified plugin to the given stack.
func (c *Client) UninstallCloudPlugin(stackSlug string, pluginSlug string) error {
return c.request("DELETE", fmt.Sprintf("/api/instances/%s/plugins/%s", stackSlug, pluginSlug), nil, nil, nil)
}

// IsCloudPluginInstalled returns a boolean if the specified plugin is installed on the stack.
func (c *Client) IsCloudPluginInstalled(stackSlug string, pluginSlug string) (bool, error) {
req, err := c.newRequest("GET", fmt.Sprintf("/api/instances/%s/plugins/%s", stackSlug, pluginSlug), nil, nil)
if err != nil {
return false, err
}

resp, err := c.client.Do(req)
if err != nil {
return false, err
}

defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
return false, nil
}
bodyContents, err := ioutil.ReadAll(resp.Body)
if err != nil {
return false, err
}

return false, fmt.Errorf("status: %d, body: %v", resp.StatusCode, string(bodyContents))
}

return true, nil
}

// GetCloudPluginInstallation returns the cloud plugin installation details for the specified plugin.
func (c *Client) GetCloudPluginInstallation(stackSlug string, pluginSlug string) (*CloudPluginInstallation, error) {
var installation CloudPluginInstallation

err := c.request("GET", fmt.Sprintf("/api/instances/%s/plugins/%s", stackSlug, pluginSlug), nil, nil, &installation)
if err != nil {
return nil, err
}

return &installation, nil
}

// PluginBySlug returns the plugin with the given slug.
// An error will be returned given an unknown slug.
func (c *Client) PluginBySlug(slug string) (*Plugin, error) {
p := Plugin{}

err := c.request("GET", fmt.Sprintf("/api/plugins/%s", slug), nil, nil, &p)
if err != nil {
return nil, err
}

return &p, nil
}

// PluginByID returns the plugin with the given id.
// An error will be returned given an unknown ID.
func (c *Client) PluginByID(pluginID int64) (*Plugin, error) {
p := Plugin{}

err := c.request("GET", fmt.Sprintf("/api/plugins/%d", pluginID), nil, nil, p)
if err != nil {
return nil, err
}

return &p, nil
}
217 changes: 217 additions & 0 deletions cloud_plugin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package gapi

import (
"testing"
)

const (
installPluginJSON = `
{
"id": 123,
"instanceId": 2,
"instanceUrl": "mystack.grafana.net",
"instanceSlug": "mystack",
"pluginId": 3,
"pluginSlug": "some-plugin",
"pluginName": "Some Plugin",
"version": "1.2.3",
"latestVersion": "1.2.3",
"createdAt": "2021-12-22T14:02:46.000Z",
"updatedAt": null
}`
uninstallPluginJSON = `
{
"id": 123,
"instanceId": 2,
"instanceUrl": "mystack.grafana.net",
"instanceSlug": "mystack",
"pluginId": 3,
"pluginSlug": "some-plugin",
"pluginName": "Some Plugin",
"version": "1.2.3",
"latestVersion": "1.2.3",
"createdAt": "2021-12-22T14:02:46.000Z",
"updatedAt": null
}`
getPluginJSON = `
{
"id": 34,
"name": "Some Plugin",
"slug": "some-plugin",
"version": "1.2.3",
"description": "Some Plugin for adding functionality"
}`
)

func TestInstallCloudPlugin(t *testing.T) {
server, client := gapiTestTools(t, 200, installPluginJSON)
defer server.Close()

installation, err := client.InstallCloudPlugin("some-stack", "some-plugin", "1.2.3")
if err != nil {
t.Error(err)
}

expectedInstallation := CloudPluginInstallation{}
err = UnmarshalJSONToStruct(installPluginJSON, &expectedInstallation)
if err != nil {
t.Fatal(err)
}

if *installation != expectedInstallation {
t.Errorf("Unexpected installation - Actual: %v, Expected: %v", installation, expectedInstallation)
}

for _, code := range []int{401, 403, 404, 412} {
server.code = code

installation, err = client.InstallCloudPlugin("some-stack", "some-plugin", "1.2.3")
if err == nil {
t.Errorf("%d not detected", code)
}
if installation != nil {
t.Errorf("Expected empty installation, got %v", installation)
}
}
}

func TestUninstallCloudPlugin(t *testing.T) {
server, client := gapiTestTools(t, 200, uninstallPluginJSON)
defer server.Close()

err := client.UninstallCloudPlugin("some-stack", "some-plugin")
if err != nil {
t.Error(err)
}

for _, code := range []int{401, 403, 404, 412} {
server.code = code

err = client.UninstallCloudPlugin("some-stack", "some-plugin")
if err == nil {
t.Errorf("%d not detected", code)
}
}
}

func TestIsCloudPluginInstalled(t *testing.T) {
server, client := gapiTestTools(t, 200, getPluginJSON)

ok, err := client.IsCloudPluginInstalled("some-stack", "some-plugin")
if err != nil {
t.Error(err)
}

if !ok {
t.Errorf("Expected plugin installation - Expected true, got false")
}

server.code = 404
ok, err = client.IsCloudPluginInstalled("some-stack", "some-plugin")
if err != nil {
t.Error(err)
}

if ok {
t.Errorf("Unexpected plugin installation - Expected false, got true")
}

for _, code := range []int{401, 403, 412} {
server.code = code

_, err := client.IsCloudPluginInstalled("some-stack", "some-plugin")
if err == nil {
t.Errorf("%d not detected", code)
}
}
}

func TestGetCloudPluginInstallation(t *testing.T) {
server, client := gapiTestTools(t, 200, installPluginJSON)
defer server.Close()

installation, err := client.GetCloudPluginInstallation("some-stack", "some-plugin")
if err != nil {
t.Error(err)
}

expectedInstallation := CloudPluginInstallation{}
err = UnmarshalJSONToStruct(installPluginJSON, &expectedInstallation)
if err != nil {
t.Fatal(err)
}

if *installation != expectedInstallation {
t.Errorf("Unexpected installation - Actual: %v, Expected: %v", installation, expectedInstallation)
}

for _, code := range []int{401, 403, 404, 412} {
server.code = code

installation, err = client.GetCloudPluginInstallation("some-stack", "some-plugin")
if err == nil {
t.Errorf("%d not detected", code)
}
if installation != nil {
t.Errorf("Expected empty installation, got %v", installation)
}
}
}

func TestPlugin(t *testing.T) {
server, client := gapiTestTools(t, 200, getPluginJSON)
defer server.Close()

plugin, err := client.PluginBySlug("some-plugin")
if err != nil {
t.Error(err)
}

expectedPlugin := Plugin{}
err = UnmarshalJSONToStruct(getPluginJSON, &expectedPlugin)
if err != nil {
t.Fatal(err)
}

if *plugin != expectedPlugin {
t.Errorf("Unexpected plugin - Actual: %v, Expected: %v", plugin, expectedPlugin)
}

for _, code := range []int{404} {
server.code = code

_, err = client.PluginBySlug("some-plugin")
if err == nil {
t.Errorf("%d not detected", code)
}
}
}

func TestPluginByID(t *testing.T) {
server, client := gapiTestTools(t, 200, getPluginJSON)
defer server.Close()

plugin, err := client.PluginBySlug("some-plugin")
if err != nil {
t.Error(err)
}

expectedPlugin := Plugin{}
err = UnmarshalJSONToStruct(getPluginJSON, &expectedPlugin)
if err != nil {
t.Fatal(err)
}

if *plugin != expectedPlugin {
t.Errorf("Unexpected plugin - Actual: %v, Expected: %v", plugin, expectedPlugin)
}

for _, code := range []int{404} {
server.code = code

_, err = client.PluginByID(123)
if err == nil {
t.Errorf("%d not detected", code)
}
}
}

0 comments on commit 075eeb6

Please sign in to comment.