forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
generic.go
138 lines (121 loc) · 5.02 KB
/
generic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package generic
import (
"encoding/json"
"fmt"
"io/ioutil"
"mime"
"net/http"
"github.com/golang/glog"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/yaml"
buildv1 "github.com/openshift/api/build/v1"
buildapi "github.com/openshift/origin/pkg/build/apis/build"
"github.com/openshift/origin/pkg/build/buildapihelpers"
"github.com/openshift/origin/pkg/build/webhook"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
// WebHookPlugin used for processing manual(or other) webhook requests.
type WebHookPlugin struct{}
// New returns a generic webhook plugin.
func New() *WebHookPlugin {
return &WebHookPlugin{}
}
// Extract services generic webhooks.
func (p *WebHookPlugin) Extract(buildCfg *buildv1.BuildConfig, trigger *buildv1.WebHookTrigger, req *http.Request) (revision *buildv1.SourceRevision, envvars []corev1.EnvVar, dockerStrategyOptions *buildv1.DockerStrategyOptions, proceed bool, err error) {
glog.V(4).Infof("Verifying build request for BuildConfig %s/%s", buildCfg.Namespace, buildCfg.Name)
if err = verifyRequest(req); err != nil {
return revision, envvars, dockerStrategyOptions, false, err
}
contentType := req.Header.Get("Content-Type")
if len(contentType) != 0 {
contentType, _, err = mime.ParseMediaType(contentType)
if err != nil {
return revision, envvars, dockerStrategyOptions, false, errors.NewBadRequest(fmt.Sprintf("error parsing Content-Type: %s", err))
}
}
if req.Body == nil {
return revision, envvars, dockerStrategyOptions, true, nil
}
if contentType != "application/json" && contentType != "application/yaml" {
warning := webhook.NewWarning("invalid Content-Type on payload, ignoring payload and continuing with build")
return revision, envvars, dockerStrategyOptions, true, warning
}
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return revision, envvars, dockerStrategyOptions, false, errors.NewBadRequest(err.Error())
}
if len(body) == 0 {
return revision, envvars, dockerStrategyOptions, true, nil
}
internalData := &buildapi.GenericWebHookEvent{}
versionedData := &buildv1.GenericWebHookEvent{}
if contentType == "application/yaml" {
body, err = yaml.ToJSON(body)
if err != nil {
warning := webhook.NewWarning(fmt.Sprintf("error converting payload to json: %v, ignoring payload and continuing with build", err))
return revision, envvars, dockerStrategyOptions, true, warning
}
}
if err = json.Unmarshal(body, &versionedData); err != nil {
warning := webhook.NewWarning(fmt.Sprintf("error unmarshalling payload: %v, ignoring payload and continuing with build", err))
return revision, envvars, dockerStrategyOptions, true, warning
}
if err := legacyscheme.Scheme.Convert(versionedData, internalData, nil); err != nil {
return revision, envvars, dockerStrategyOptions, false, errors.NewBadRequest(err.Error())
}
if len(versionedData.Env) > 0 && trigger.AllowEnv {
envvars = versionedData.Env
}
if internalData.DockerStrategyOptions != nil {
dockerStrategyOptions = versionedData.DockerStrategyOptions
}
if buildCfg.Spec.Source.Git == nil {
// everything below here is specific to git-based builds
return revision, envvars, dockerStrategyOptions, true, nil
}
if internalData.Git == nil {
warning := webhook.NewWarning("no git information found in payload, ignoring and continuing with build")
return revision, envvars, dockerStrategyOptions, true, warning
}
if internalData.Git.Refs != nil {
for _, ref := range versionedData.Git.Refs {
if webhook.GitRefMatches(ref.Ref, webhook.DefaultConfigRef, &buildCfg.Spec.Source) {
revision = &buildv1.SourceRevision{
Git: &ref.GitSourceRevision,
}
return revision, envvars, dockerStrategyOptions, true, nil
}
}
warning := webhook.NewWarning(fmt.Sprintf("skipping build. None of the supplied refs matched %q", buildCfg.Spec.Source.Git.Ref))
return revision, envvars, dockerStrategyOptions, false, warning
}
if !webhook.GitRefMatches(internalData.Git.Ref, webhook.DefaultConfigRef, &buildCfg.Spec.Source) {
warning := webhook.NewWarning(fmt.Sprintf("skipping build. Branch reference from %q does not match configuration", internalData.Git.Ref))
return revision, envvars, dockerStrategyOptions, false, warning
}
revision = &buildv1.SourceRevision{
Git: &versionedData.Git.GitSourceRevision,
}
return revision, envvars, dockerStrategyOptions, true, nil
}
// GetTriggers retrieves the WebHookTriggers for this webhook type (if any)
func (p *WebHookPlugin) GetTriggers(buildConfig *buildv1.BuildConfig) ([]*buildv1.WebHookTrigger, error) {
triggers := buildapihelpers.FindTriggerPolicy(buildv1.GenericWebHookBuildTriggerType, buildConfig)
webhookTriggers := []*buildv1.WebHookTrigger{}
for _, trigger := range triggers {
if trigger.GenericWebHook != nil {
webhookTriggers = append(webhookTriggers, trigger.GenericWebHook)
}
}
if len(webhookTriggers) == 0 {
return nil, webhook.ErrHookNotEnabled
}
return webhookTriggers, nil
}
func verifyRequest(req *http.Request) error {
if req.Method != "POST" {
return webhook.MethodNotSupported
}
return nil
}