Skip to content

Commit fd05d9e

Browse files
committed
added readme and fixed some bugs
1 parent 3b42bb8 commit fd05d9e

File tree

4 files changed

+153
-57
lines changed

4 files changed

+153
-57
lines changed

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# Argocd Executor Plugin
2-
**IN ACTIVE DEVELOPMENT**
3-
4-
This is an ArgoCD plugin that allows you to interact with an argocd instance of your choice.
5-
This is meant to be easily available and to be used in your ci/cd needs.
1+
<div align="center">
2+
<h1 align="center">Argocd Executor Plugin</h1>
3+
<p align="center">An <a href="https://github.com/argoproj/argo-workflows/blob/master/docs/executor_plugins.md">Executor Plugin</a> for <a href="https://argoproj.github.io/argo-workflows/">Argo Workflows</a> that lets you interact with ArgoCD servers </br>
4+
<b>In Active Development</b></p>
5+
</div>
66

77
## Example Usage
88

@@ -23,8 +23,11 @@ spec:
2323
project: guestbook
2424
apps:
2525
- guestbook
26+
- guestbook-backend
2627
```
2728
29+
</br>
30+
2831
## Getting Started
2932
3033
Head to the [scripts](scripts/README.md) directory to find out how to get the project up and running on your local machine for development and testing purposes.
@@ -37,6 +40,8 @@ You will need to have a working [Argo Workflows](https://argoproj.github.io/argo
3740
3841
Read how to install the plugin in your Argo Workflows instance [here](out/README.md).
3942
43+
</br>
44+
4045
## Contributing
4146
4247
Currently I am developing this on my own as my interest in workflow plugins is growing. <br>

cmd/argocd-plugin/main.go

Lines changed: 2 additions & 2 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-
argocd "github.com/UrielCohen456/argo-workflows-argocd-executor-plugin/internal/argocd-plugin"
10+
plugin "github.com/UrielCohen456/argo-workflows-argocd-executor-plugin/internal/argocd-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", argocd.ArgocdPlugin(client, common.Namespace()))
24+
http.HandleFunc("/api/v1/template.execute", plugin.ArgocdPlugin(client, common.Namespace()))
2525
http.ListenAndServe(":4355", nil)
2626
}

internal/argocd-plugin/plugin.go

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,64 @@ package argocd
22

33
import (
44
"encoding/json"
5+
"errors"
56
"fmt"
67
"io/ioutil"
78
"log"
89
"net/http"
910

1011
"k8s.io/client-go/kubernetes"
1112
// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12-
"github.com/argoproj/argo-workflows/v3/pkg/plugins/executor"
13+
"github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
14+
"github.com/argoproj/argo-workflows/v3/pkg/plugins/executor"
15+
)
16+
17+
var (
18+
ErrWrongContentType = errors.New("Content-Type header is not set to 'appliaction/json'")
19+
ErrReadingBody = errors.New("Couldn't read request body")
20+
ErrMarshallingBody = errors.New("Couldn't unmrashal request body")
1321
)
1422

1523
func ArgocdPlugin(kubeClient kubernetes.Interface, namespace string) func(w http.ResponseWriter, req *http.Request) {
1624
return func(w http.ResponseWriter, req *http.Request) {
17-
if req.Body == http.NoBody {
18-
log.Printf("No request body present")
19-
http.Error(w, "No request body present", http.StatusBadRequest)
25+
if header := req.Header.Get("Content-Type"); header == "" || header != "application/json" {
26+
log.Print(ErrWrongContentType)
27+
http.Error(w, ErrWrongContentType.Error(), http.StatusBadRequest)
2028
return
2129
}
2230

2331
body, err := ioutil.ReadAll(req.Body)
2432
if err != nil {
25-
log.Printf("Error reading body: %v", err)
26-
http.Error(w, "couldn't read body", http.StatusBadRequest)
33+
log.Print(ErrReadingBody)
34+
http.Error(w, ErrReadingBody.Error(), http.StatusBadRequest)
2735
return
2836
}
2937

38+
log.Printf("Recieved body: %v", string(body))
39+
3040
args := executor.ExecuteTemplateArgs{}
31-
if err := args.Template.Unmarshal(body); err != nil {
32-
log.Printf("Error unmrashalling body: %v", err)
33-
http.Error(w, "couldn't unmrashal body", http.StatusBadRequest)
41+
if err := json.Unmarshal(body, &args); err != nil {
42+
log.Print(ErrMarshallingBody)
43+
http.Error(w, ErrMarshallingBody.Error(), http.StatusBadRequest)
3444
return
3545
}
36-
log.Printf("%v", args)
46+
47+
log.Printf("Received args: %v", args)
3748

3849
// channel, text, err := parsPayload(args)
3950
// if err != nil {
4051
// w.WriteHeader(http.StatusBadRequest)
4152
// return
4253
// }
4354

44-
resp := make(map[string]map[string]string)
45-
resp["node"] = make(map[string]string)
46-
resp["node"]["phase"] = "Succeeded"
47-
resp["node"]["message"] = fmt.Sprintf("ArgoCD command succeeded: %s", namespace)
48-
resp["node"]["debug"] = fmt.Sprint(args)
55+
resp := executor.ExecuteTemplateResponse{
56+
Body: executor.ExecuteTemplateReply{
57+
Node: &v1alpha1.NodeResult{
58+
Phase: v1alpha1.NodePhase("Succeeded"),
59+
Message: fmt.Sprintf("ArgoCD command succeeded: %s", namespace),
60+
},
61+
},
62+
}
4963

5064
jsonResp, err := json.Marshal(resp)
5165
if err != nil {

internal/argocd-plugin/plugin_test.go

Lines changed: 112 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,141 @@ package argocd
22

33
import (
44
"bytes"
5-
"encoding/json"
5+
"errors"
6+
"io"
67
"net/http"
78
"net/http/httptest"
9+
"strings"
810
"testing"
911

1012
"github.com/UrielCohen456/argo-workflows-argocd-executor-plugin/common"
11-
"github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
12-
"github.com/argoproj/argo-workflows/v3/pkg/plugins/executor"
1313
"k8s.io/client-go/kubernetes/fake"
14-
// "github.com/stretchr/testify/assert"
1514
)
1615

1716
var (
18-
workflow, _ = json.Marshal(json.RawMessage(`{"foo": "bar"}`))
17+
headerEmpty = map[string]string{}
18+
headerContentJson = map[string]string{"Content-Type": "application/json"}
19+
headerContentEncoded = map[string]string{"Content-Type": "application/x-www-form-urlencoded"}
1920
)
21+
22+
type errReader int
23+
24+
func (errReader) Read(p []byte) (n int, err error) {
25+
return 0, errors.New("Read error")
26+
}
27+
2028
func TestArgocdPlugin(t *testing.T) {
21-
var tests = []struct {
29+
// test trying to invoke execute on argocd action
30+
// test returning currect result based on input
31+
32+
kubeClient := fake.NewSimpleClientset()
33+
argocdPlugin := ArgocdPlugin(kubeClient, "argo")
34+
handler := http.HandlerFunc(argocdPlugin)
35+
36+
var failTests = []struct {
2237
name string
23-
request executor.ExecuteTemplateArgs
38+
body io.Reader
39+
headers map[string]string
2440
want string
2541
status int
2642
}{
2743
{
28-
"parse body and return success",
29-
executor.ExecuteTemplateArgs{
30-
Workflow: &executor.Workflow{
31-
ObjectMeta: executor.ObjectMeta{Name: "workflow"},
32-
},
33-
Template: &v1alpha1.Template{
34-
Name: "my-tmpl",
35-
Plugin: &v1alpha1.Plugin{
36-
Object: v1alpha1.Object{Value: json.RawMessage(
37-
`{
38-
"argocd": {}
39-
}`)},
40-
},
41-
},
42-
},
43-
`{"node": { "phase": "Succeeded", "message": "Succeeded"}}`,
44-
http.StatusOK,
44+
name: "fail header content-type is empty",
45+
body: nil,
46+
headers: headerEmpty,
47+
want: ErrWrongContentType.Error(),
48+
status: http.StatusBadRequest,
49+
},
50+
{
51+
name: "fail header content-type is not application/json",
52+
body: nil,
53+
headers: headerContentEncoded,
54+
want: ErrWrongContentType.Error(),
55+
status: http.StatusBadRequest,
56+
},
57+
{
58+
name: "fail reading body",
59+
body: errReader(0),
60+
headers: headerContentJson,
61+
want: ErrReadingBody.Error(),
62+
status: http.StatusBadRequest,
63+
},
64+
{
65+
name: "fail marshalling body",
66+
body: bytes.NewReader([]byte(`"lol": "test"`)),
67+
headers: headerContentJson,
68+
want: ErrMarshallingBody.Error(),
69+
status: http.StatusBadRequest,
70+
},
71+
{
72+
name: "succeed marshalling body",
73+
body: bytes.NewReader([]byte(`"lol": "test"`)),
74+
headers: headerContentJson,
75+
want: "Success",
76+
status: http.StatusBadRequest,
4577
},
4678
}
4779

48-
kubeClient := fake.NewSimpleClientset()
49-
argocdPlugin := ArgocdPlugin(kubeClient, "argo")
50-
handler := http.HandlerFunc(argocdPlugin)
51-
52-
for _, tt := range tests {
80+
for _, tt := range failTests {
5381
t.Run(tt.name, func(t *testing.T) {
54-
body, _ := json.Marshal(&tt.request)
55-
request, _ := http.NewRequest(http.MethodPost, "/api/v1/template.execute", bytes.NewReader(body))
82+
request, _ := http.NewRequest(http.MethodPost, "/api/v1/template.execute", tt.body)
83+
for key, value := range tt.headers {
84+
request.Header.Set(key, value)
85+
}
5686
response := httptest.NewRecorder()
57-
5887
handler.ServeHTTP(response, request)
59-
6088

61-
common.AssertResponseBody(t, response.Body.String(), tt.want)
62-
common.AssertStatus(t, response.Code, tt.status)
89+
got := strings.Trim(response.Body.String(), "\n")
90+
gotStatus := response.Code
91+
92+
common.AssertResponseBody(t, got, tt.want)
93+
common.AssertStatus(t, gotStatus, tt.status)
6394
})
6495
}
96+
6597
}
98+
99+
// var tests = []struct {
100+
// name string
101+
// request executor.ExecuteTemplateArgs
102+
// want string
103+
// status int
104+
// }{
105+
// {
106+
// "parse body and return success",
107+
// executor.ExecuteTemplateArgs{
108+
// Workflow: &executor.Workflow{
109+
// ObjectMeta: executor.ObjectMeta{Name: "workflow"},
110+
// },
111+
// Template: &v1alpha1.Template{
112+
// Name: "my-tmpl",
113+
// Plugin: &v1alpha1.Plugin{
114+
// Object: v1alpha1.Object{Value: json.RawMessage(
115+
// `{
116+
// "argocd": {}
117+
// }`)},
118+
// },
119+
// },
120+
// },
121+
// `{"node": { "phase": "Succeeded", "message": "Succeeded"}}`,
122+
// http.StatusOK,
123+
// },
124+
// }
125+
126+
// kubeClient := fake.NewSimpleClientset()
127+
// argocdPlugin := ArgocdPlugin(kubeClient, "argo")
128+
// handler := http.HandlerFunc(argocdPlugin)
129+
130+
// for _, tt := range tests {
131+
// t.Run(tt.name, func(t *testing.T) {
132+
// body, _ := json.Marshal(&tt.request)
133+
// request, _ := http.NewRequest(http.MethodPost, "/api/v1/template.execute", bytes.NewReader(body))
134+
// response := httptest.NewRecorder()
135+
136+
// handler.ServeHTTP(response, request)
137+
138+
139+
// common.AssertResponseBody(t, response.Body.String(), tt.want)
140+
// common.AssertStatus(t, response.Code, tt.status)
141+
// })
142+
// }

0 commit comments

Comments
 (0)