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
|
package agent
import (
"context"
"fmt"
"net/http"
"net/url"
"path"
"regexp"
"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v16/internal/tool/errz"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
)
const (
defaultServiceAPIBaseURL = "http://webhook-receiver.flux-system.svc.cluster.local"
)
var (
kubeProxyAPIPathRegex = regexp.MustCompile("/api/v1/namespaces/[^/]+/services/[^/]+/proxy")
)
type reconcileTrigger interface {
reconcile(ctx context.Context, webhookPath string) error
}
type gitrepositoryReconcileTrigger struct {
baseURL url.URL
rt http.RoundTripper
}
func newGitRepositoryReconcileTrigger(cfgURL string, kubeAPIURL *url.URL, kubeAPIRoundTripper http.RoundTripper, defaultRoundTripper http.RoundTripper) (*gitrepositoryReconcileTrigger, error) {
if kubeProxyAPIPathRegex.MatchString(cfgURL) {
u := *kubeAPIURL
u.Path = path.Join(u.Path, cfgURL)
return &gitrepositoryReconcileTrigger{baseURL: u, rt: kubeAPIRoundTripper}, nil
} else {
u, err := url.Parse(cfgURL)
if err != nil {
return nil, err
}
return &gitrepositoryReconcileTrigger{baseURL: *u, rt: defaultRoundTripper}, nil
}
}
func (t *gitrepositoryReconcileTrigger) reconcile(ctx context.Context, webhookPath string) (retErr error) {
u := t.baseURL
u.Path = path.Join(u.Path, webhookPath)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), http.NoBody)
if err != nil {
return err
}
resp, err := t.rt.RoundTrip(req) //nolint:bodyclose
if err != nil {
return err
}
defer errz.DiscardAndClose(resp.Body, &retErr)
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("trigger to %q returned status %q", u.String(), resp.Status)
}
return nil
}
// This is a copy from k8s.io/client-go/rest/url_utils.go
// defaultServerURLFor is shared between IsConfigTransportTLS and RESTClientFor. It
// requires Host and Version to be set prior to being called.
func defaultServerURLFor(config *rest.Config) (*url.URL, string, error) {
// TODO: move the default to secure when the apiserver supports TLS by default
// config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA."
hasCA := len(config.CAFile) != 0 || len(config.CAData) != 0
hasCert := len(config.CertFile) != 0 || len(config.CertData) != 0
defaultTLS := hasCA || hasCert || config.Insecure
host := config.Host
if host == "" {
host = "localhost"
}
if config.GroupVersion != nil {
return rest.DefaultServerURL(host, config.APIPath, *config.GroupVersion, defaultTLS)
}
return rest.DefaultServerURL(host, config.APIPath, schema.GroupVersion{}, defaultTLS)
}
|