Skip to content

Commit 9f092bd

Browse files
committed
finished building the skeleton for the plugin, can now work on the argocd plugin itself. also moved it to external pkg incase anyone wants to use this skeleton themselves
1 parent 9d6d789 commit 9f092bd

File tree

8 files changed

+173
-128
lines changed

8 files changed

+173
-128
lines changed

cmd/argocd-plugin/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"k8s.io/client-go/rest"
88

99
"github.com/UrielCohen456/argo-workflows-argocd-executor-plugin/common"
10-
plugin "github.com/UrielCohen456/argo-workflows-argocd-executor-plugin/internal/argocd-plugin"
10+
"github.com/UrielCohen456/argo-workflows-argocd-executor-plugin/pkg/plugin"
1111
)
1212

1313
func main() {
@@ -21,6 +21,6 @@ func main() {
2121
panic(err.Error())
2222
}
2323

24-
http.HandleFunc("/api/v1/template.execute", plugin.ArgocdPlugin(client, common.Namespace()))
25-
http.ListenAndServe(":4355", nil)
24+
http.HandleFunc("/api/v1/template.execute", plugin.ArgocdPlugin(client, common.Namespace()))
25+
http.ListenAndServe(":3000", nil)
2626
}

deployments/plugin.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ spec:
1313
name: argocd-executor-plugin
1414
image: urielc12/argocd-plugin
1515
ports:
16-
- containerPort: 4355
16+
- containerPort: 3000
1717
resources:
1818
requests:
1919
cpu: 100m

internal/argocd-plugin/plugin.go

Lines changed: 0 additions & 93 deletions
This file was deleted.

internal/argocd.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package argocd
2+
3+
4+
5+
// output, err := exec.Command("argocd").Output()
6+
// if err!=nil {
7+
// fmt.Println(err.Error())
8+
// }
9+
// fmt.Println(string(output))
10+
11+
// pods, err := clientSet.CoreV1().Pods(ctx.Value("namespace").(string)).List(ctx, metav1.ListOptions{})
12+
// if err != nil {
13+
// panic(err.Error())
14+
// }
15+
// fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
16+
17+
// _, err = clientSet.CoreV1().Pods("default").Get(ctx, "example-xxxxx", metav1.GetOptions{})
18+
// if errors.IsNotFound(err) {
19+
// fmt.Printf("Pod example-xxxxx not found in default namespace\n")
20+
// } else if statusError, isStatus := err.(*errors.StatusError); isStatus {
21+
// fmt.Printf("Error getting pod %v\n", statusError.ErrStatus.Message)
22+
// } else if err != nil {
23+
// panic(err.Error())
24+
// } else {
25+
// fmt.Printf("Found example-xxxxx pod in default namespace\n")
26+
// }

internal/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package types
1+
package argocd
22

33
// wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
44
// "github.com/argoproj/argo-workflows/v3/pkg/plugins/executor"

pkg/.keep

Whitespace-only changes.

pkg/plugin.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package plugin
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"io/ioutil"
7+
"log"
8+
"net/http"
9+
10+
"k8s.io/client-go/kubernetes"
11+
// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
13+
executor "github.com/argoproj/argo-workflows/v3/pkg/plugins/executor"
14+
)
15+
16+
var (
17+
ErrWrongContentType = errors.New("Content-Type header is not set to 'appliaction/json'")
18+
ErrReadingBody = errors.New("Couldn't read request body")
19+
ErrMarshallingBody = errors.New("Couldn't unmrashal request body")
20+
ErrExecutingPlugin = errors.New("Error occured while executing plugin")
21+
)
22+
23+
// The plugin's logic
24+
type PluginExecutor interface {
25+
// Executes commands based on the args provided from the workflow
26+
Execute(args executor.ExecuteTemplateArgs) (executor.ExecuteTemplateResponse, error)
27+
}
28+
29+
func ArgocdPlugin(plugin PluginExecutor, kubeClient kubernetes.Interface, namespace string) func(w http.ResponseWriter, req *http.Request) {
30+
return func(w http.ResponseWriter, req *http.Request) {
31+
if header := req.Header.Get("Content-Type"); header == "" || header != "application/json" {
32+
log.Print(ErrWrongContentType)
33+
http.Error(w, ErrWrongContentType.Error(), http.StatusBadRequest)
34+
return
35+
}
36+
37+
body, err := ioutil.ReadAll(req.Body)
38+
if err != nil {
39+
log.Printf("%v: %v", ErrReadingBody.Error(), err)
40+
http.Error(w, ErrReadingBody.Error(), http.StatusBadRequest)
41+
return
42+
}
43+
44+
args := executor.ExecuteTemplateArgs{}
45+
if err := json.Unmarshal(body, &args); err != nil || args.Workflow == nil || args.Template == nil {
46+
log.Printf("%v: %v", ErrMarshallingBody.Error(), err)
47+
http.Error(w, ErrMarshallingBody.Error(), http.StatusBadRequest)
48+
return
49+
}
50+
51+
resp, err := plugin.Execute(args)
52+
if err != nil {
53+
log.Printf("%v: %v", ErrExecutingPlugin.Error(), err)
54+
http.Error(w, ErrExecutingPlugin.Error(), http.StatusInternalServerError)
55+
return
56+
}
57+
58+
jsonResp, err := json.Marshal(resp)
59+
if err != nil {
60+
log.Printf("Error marshalling result: %v", err)
61+
http.Error(w, "something went wrong", http.StatusBadRequest)
62+
}
63+
64+
w.WriteHeader(http.StatusOK)
65+
w.Write(jsonResp)
66+
return
67+
}
68+
}

internal/argocd-plugin/plugin_test.go renamed to pkg/plugin_test.go

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package argocd
1+
package plugin
22

33
import (
44
"bytes"
@@ -10,13 +10,31 @@ import (
1010
"testing"
1111

1212
"github.com/UrielCohen456/argo-workflows-argocd-executor-plugin/common"
13+
"github.com/argoproj/argo-workflows/v3/pkg/plugins/executor"
1314
"k8s.io/client-go/kubernetes/fake"
1415
)
1516

1617
var (
1718
headerEmpty = map[string]string{}
1819
headerContentJson = map[string]string{"Content-Type": "application/json"}
1920
headerContentEncoded = map[string]string{"Content-Type": "application/x-www-form-urlencoded"}
21+
validWorkflowBody = []byte(
22+
`{
23+
"workflow": {
24+
"metadata": {
25+
"name": "test-template"
26+
}
27+
},
28+
"template": {
29+
"name": "plugin",
30+
"inputs": {},
31+
"outputs": {},
32+
"plugin": {
33+
"any": {
34+
}
35+
}
36+
}
37+
}`)
2038
)
2139

2240
type errReader int
@@ -25,12 +43,29 @@ func (errReader) Read(p []byte) (n int, err error) {
2543
return 0, errors.New("Read error")
2644
}
2745

46+
type executorSpy struct {
47+
48+
Called bool
49+
Fail bool
50+
}
51+
52+
func (e *executorSpy) Execute(args executor.ExecuteTemplateArgs) (executor.ExecuteTemplateResponse, error) {
53+
var err error = nil
54+
55+
if e.Fail {
56+
err = ErrExecutingPlugin
57+
}
58+
e.Called = true
59+
60+
return executor.ExecuteTemplateResponse{}, err
61+
}
62+
2863
func TestArgocdPlugin(t *testing.T) {
29-
// test trying to invoke execute on argocd action
3064
// test returning currect result based on input
3165

3266
kubeClient := fake.NewSimpleClientset()
33-
argocdPlugin := ArgocdPlugin(kubeClient, "argo")
67+
spy := executorSpy{}
68+
argocdPlugin := ArgocdPlugin(&spy, kubeClient, "argo")
3469
handler := http.HandlerFunc(argocdPlugin)
3570

3671
var failTests = []struct {
@@ -80,38 +115,47 @@ func TestArgocdPlugin(t *testing.T) {
80115
handler.ServeHTTP(response, request)
81116

82117
got := strings.Trim(response.Body.String(), "\n")
83-
gotStatus := response.Code
118+
gotStatus := response.Result().StatusCode
84119

85120
common.AssertResponseBody(t, got, tt.want)
86121
common.AssertStatus(t, gotStatus, tt.status)
87122
})
88123
}
89124

90-
t.Run("succeed marshalling body and execute the request", func(t *testing.T) {
91-
body := bytes.NewReader([]byte(
92-
`{
93-
"workflow": {
94-
"metadata": {
95-
"name": "test-template"
96-
}
97-
},
98-
"template": {
99-
"name": "argocd-plugin",
100-
"inputs": {},
101-
"outputs": {},
102-
"plugin": {
103-
"argocd": {
104-
}
105-
}
125+
var execTests = []struct {
126+
name string
127+
fail bool
128+
status int
129+
}{
130+
{
131+
name: "exec without fail",
132+
fail: false,
133+
status: http.StatusOK,
134+
},
135+
{
136+
name: "exec fails",
137+
fail: true,
138+
status: http.StatusInternalServerError,
139+
},
106140
}
107-
}`))
108-
request, _ := http.NewRequest(http.MethodPost, "/api/v1/template.execute", body)
109-
request.Header.Set("Content-Type", "application/json")
110-
response := httptest.NewRecorder()
111-
handler.ServeHTTP(response, request)
112-
113-
got := response.Code
114-
115-
common.AssertStatus(t, got, http.StatusOK)
116-
})
141+
142+
body := validWorkflowBody
143+
for _, tt := range execTests {
144+
t.Run(tt.name, func(t *testing.T) {
145+
spy.Called = false
146+
spy.Fail = tt.fail
147+
request, _ := http.NewRequest(http.MethodPost, "/api/v1/template.execute", bytes.NewReader(body))
148+
request.Header.Set("Content-Type", "application/json")
149+
response := httptest.NewRecorder()
150+
handler.ServeHTTP(response, request)
151+
152+
if !spy.Called && !tt.fail {
153+
t.Error("Executor was not called")
154+
}
155+
156+
got := response.Result().StatusCode
157+
158+
common.AssertStatus(t, got, tt.status)
159+
})
160+
}
117161
}

0 commit comments

Comments
 (0)