Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NOISSUE - Add SDK and tasks management on CLI #34

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading