Skip to content

Commit

Permalink
Merge pull request #34 from absmach/manager-sdk
Browse files Browse the repository at this point in the history
NOISSUE - Add SDK and tasks management on CLI
  • Loading branch information
drasko authored Dec 13, 2024
2 parents 2d3234c + a9e3591 commit 158d0f0
Show file tree
Hide file tree
Showing 8 changed files with 531 additions and 2 deletions.
1 change: 1 addition & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ linters:
- interfacebloat
- dupl
- err113
- noctx

linters-settings:
gocritic:
Expand Down
11 changes: 11 additions & 0 deletions cmd/propellerd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"log"

"github.com/absmach/propeller/pkg/sdk"
"github.com/absmach/propeller/propellerd"
"github.com/spf13/cobra"
)
Expand All @@ -12,11 +13,21 @@ func main() {
Use: "propellerd",
Short: "Propeller Daemon",
Long: `Propeller Daemon is a daemon that manages the lifecycle of Propeller components.`,
PersistentPreRun: func(_ *cobra.Command, _ []string) {
sdkConf := sdk.Config{
ManagerURL: propellerd.DefManagerURL,
TLSVerification: propellerd.DefTLSVerification,
}
s := sdk.NewSDK(sdkConf)
propellerd.SetSDK(s)
},
}

managerCmd := propellerd.NewManagerCmd()
tasksCmd := propellerd.NewTasksCmd()

rootCmd.AddCommand(managerCmd)
rootCmd.AddCommand(tasksCmd)

if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
Expand Down
8 changes: 6 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ require (
github.com/0x6flab/namegenerator v1.4.0
github.com/absmach/magistrala v0.15.1
github.com/eclipse/paho.mqtt.golang v1.5.0
github.com/fatih/color v1.18.0
github.com/go-chi/chi/v5 v5.1.0
github.com/go-kit/kit v0.13.0
github.com/google/uuid v1.6.0
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f
github.com/prometheus/client_golang v1.20.5
github.com/spf13/cobra v1.8.1
github.com/tetratelabs/wazero v1.8.2
Expand All @@ -31,6 +33,8 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.61.0 // indirect
Expand All @@ -44,8 +48,8 @@ require (
golang.org/x/net v0.32.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/grpc v1.68.1 // indirect
google.golang.org/protobuf v1.35.2 // indirect
)
Expand Down
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
Expand All @@ -40,12 +42,19 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8=
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
Expand Down Expand Up @@ -87,14 +96,20 @@ golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583 h1:v+j+5gpj0FopU0KKLDGfDo9ZRRpKdi5UBrCP0f76kuY=
google.golang.org/genproto/googleapis/api v0.0.0-20241206012308-a4fef0638583/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 h1:IfdSdTcLFy4lqUQrQJLkLt1PB+AsqVz6lwkWPzWEz10=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
Expand Down
122 changes: 122 additions & 0 deletions pkg/sdk/sdk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package sdk

import (
"bytes"
"crypto/tls"
"fmt"
"io"
"net/http"
)

const CTJSON string = "application/json"

type PageMetadata struct {
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
}

type SDK interface {
// CreateTask creates a new task.
//
// example:
// task := sdk.Task{
// Name: "John Doe"
// }
// task, _ := sdk.CreateTask(task)
// fmt.Println(task)
CreateTask(task Task) (Task, error)

// GetTask gets a task by id.
//
// example:
// task, _ := sdk.GetTask("b1d10738-c5d7-4ff1-8f4d-b9328ce6f040")
// fmt.Println(task)
GetTask(id string) (Task, error)

// ListTasks lists tasks.
//
// example:
// taskPage, _ := sdk.ListTasks(0, 10)
// fmt.Println(taskPage)
ListTasks(offset uint64, limit uint64) (TaskPage, error)

// UpdateTask updates a task.
//
// example:
// task := sdk.Task{
// Name: "John Doe"
// }
// task, _ := sdk.UpdateTask(task)
// fmt.Println(task)
UpdateTask(task Task) (Task, error)

// DeleteTask deletes a task.
//
// example:
// task, _ := sdk.DeleteTask("b1d10738-c5d7-4ff1-8f4d-b9328ce6f040")
// fmt.Println(task)
DeleteTask(id string) error

// StartTask starts a task.
//
// example:
// task, _ := sdk.StartTask("b1d10738-c5d7-4ff1-8f4d-b9328ce6f040")
// fmt.Println(task)
StartTask(id string) error

// StopTask stops a task.
//
// example:
// task, _ := sdk.StopTask("b1d10738-c5d7-4ff1-8f4d-b9328ce6f040")
// fmt.Println(task)
StopTask(id string) error
}

type propSDK struct {
managerURL string
client *http.Client
}

type Config struct {
ManagerURL string
TLSVerification bool
}

func NewSDK(cfg Config) SDK {
return &propSDK{
managerURL: cfg.ManagerURL,
client: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: !cfg.TLSVerification,
},
},
},
}
}

func (sdk *propSDK) processRequest(method, reqURL string, data []byte, expectedRespCode int) ([]byte, error) {
req, err := http.NewRequest(method, reqURL, bytes.NewReader(data))
if err != nil {
return []byte{}, err
}

req.Header.Add("Content-Type", CTJSON)

resp, err := sdk.client.Do(req)
if err != nil {
return []byte{}, err
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return []byte{}, err
}

if resp.StatusCode != expectedRespCode {
return []byte{}, fmt.Errorf("unexpected response code: %d", resp.StatusCode)
}

return body, nil
}
142 changes: 142 additions & 0 deletions pkg/sdk/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package sdk

import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
)

const tasksEndpoint = "/tasks"

type Task struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
State uint8 `json:"state,omitempty"`
StartTime time.Time `json:"start_time"`
FinishTime time.Time `json:"finish_time"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

type TaskPage struct {
Offset uint64 `json:"offset"`
Limit uint64 `json:"limit"`
Total uint64 `json:"total"`
Tasks []Task `json:"tasks"`
}

func (sdk *propSDK) CreateTask(task Task) (Task, error) {
data, err := json.Marshal(task)
if err != nil {
return Task{}, err
}

url := sdk.managerURL + tasksEndpoint

body, err := sdk.processRequest(http.MethodPost, url, data, http.StatusCreated)
if err != nil {
return Task{}, err
}

var t Task
if err := json.Unmarshal(body, &t); err != nil {
return Task{}, err
}

return t, nil
}

func (sdk *propSDK) GetTask(id string) (Task, error) {
url := sdk.managerURL + tasksEndpoint + "/" + id

body, err := sdk.processRequest(http.MethodGet, url, nil, http.StatusOK)
if err != nil {
return Task{}, err
}

var t Task
if err := json.Unmarshal(body, &t); err != nil {
return Task{}, err
}

return t, nil
}

func (sdk *propSDK) ListTasks(offset, limit uint64) (TaskPage, error) {
queries := make([]string, 0)
if offset > 0 {
queries = append(queries, fmt.Sprintf("offset=%d", offset))
}
if limit > 0 {
queries = append(queries, fmt.Sprintf("limit=%d", limit))
}
query := ""
if len(queries) > 0 {
query = "?" + strings.Join(queries, "&")
}
url := sdk.managerURL + tasksEndpoint + query

body, err := sdk.processRequest(http.MethodGet, url, nil, http.StatusOK)
if err != nil {
return TaskPage{}, err
}

var t TaskPage
if err := json.Unmarshal(body, &t); err != nil {
return TaskPage{}, err
}

return t, nil
}

func (sdk *propSDK) UpdateTask(task Task) (Task, error) {
data, err := json.Marshal(task)
if err != nil {
return Task{}, err
}
url := sdk.managerURL + tasksEndpoint + "/" + task.ID

body, err := sdk.processRequest(http.MethodPut, url, data, http.StatusOK)
if err != nil {
return Task{}, err
}

var t Task
if err := json.Unmarshal(body, &t); err != nil {
return Task{}, err
}

return t, nil
}

func (sdk *propSDK) DeleteTask(id string) error {
url := sdk.managerURL + tasksEndpoint + "/" + id

if _, err := sdk.processRequest(http.MethodDelete, url, nil, http.StatusNoContent); err != nil {
return err
}

return nil
}

func (sdk *propSDK) StartTask(id string) error {
url := fmt.Sprintf("%s/tasks/%s/start", sdk.managerURL, id)

if _, err := sdk.processRequest(http.MethodPost, url, nil, http.StatusOK); err != nil {
return err
}

return nil
}

func (sdk *propSDK) StopTask(id string) error {
url := fmt.Sprintf("%s/tasks/%s/stop", sdk.managerURL, id)

if _, err := sdk.processRequest(http.MethodPost, url, nil, http.StatusOK); err != nil {
return err
}

return nil
}
Loading

0 comments on commit 158d0f0

Please sign in to comment.