Skip to content

Commit

Permalink
tracked image set endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
rusenask committed May 26, 2019
1 parent 0e73b90 commit 3657453
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 19 deletions.
5 changes: 5 additions & 0 deletions cmd/keel/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const (
EnvDataDir = "DATA_DIR"
EnvHelmProvider = "HELM_PROVIDER" // helm provider
EnvHelmTillerAddress = "TILLER_ADDRESS" // helm provider
EnvUIDir = "UI_DIR"

// EnvDefaultDockerRegistryCfg - default registry configuration that can be passed into
// keel for polling trigger
Expand All @@ -81,6 +82,7 @@ func main() {

inCluster := kingpin.Flag("incluster", "use in cluster configuration (defaults to 'true'), use '--no-incluster' if running outside of the cluster").Default("true").Bool()
kubeconfig := kingpin.Flag("kubeconfig", "path to kubeconfig (if not in running inside a cluster)").Default(filepath.Join(os.Getenv("HOME"), ".kube", "config")).String()
uiDir := kingpin.Flag("ui-dir", "path to web UI static files").Default("").Envar(EnvUIDir).String()

kingpin.UsageTemplate(kingpin.CompactUsageTemplate).Version(ver.Version)
kingpin.CommandLine.Help = "Automated Kubernetes deployment updates. Learn more on https://keel.sh."
Expand Down Expand Up @@ -225,6 +227,7 @@ func main() {
grc: &t.GenericResourceCache,
k8sClient: implementer,
store: sqlStore,
uiDir: *uiDir,
})

bot.Run(implementer, approvalsManager)
Expand Down Expand Up @@ -316,6 +319,7 @@ type TriggerOpts struct {
grc *k8s.GenericResourceCache
k8sClient kubernetes.Implementer
store store.Store
uiDir string
}

// setupTriggers - setting up triggers. New triggers should be added to this function. Each trigger
Expand All @@ -338,6 +342,7 @@ func setupTriggers(ctx context.Context, opts *TriggerOpts) (teardown func()) {
ApprovalManager: opts.approvalsManager,
Store: opts.store,
Authenticator: authenticator,
UIDir: opts.uiDir,
})

go func() {
Expand Down
40 changes: 31 additions & 9 deletions pkg/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ type Opts struct {
ApprovalManager approvals.Manager

Authenticator auth.Authenticator
// Username and password are used for basic auth
// Username string
// Password string

GRC *k8s.GenericResourceCache

KubernetesClient kubernetes.Implementer

Store store.Store

UIDir string
}

// TriggerServer - webhook trigger & healthcheck server
Expand All @@ -62,9 +61,7 @@ type TriggerServer struct {
store store.Store
authenticator auth.Authenticator

// basic auth
// username string
// password string
uiDir string
}

// NewTriggerServer - create new HTTP trigger based server
Expand All @@ -77,9 +74,8 @@ func NewTriggerServer(opts *Opts) *TriggerServer {
approvalsManager: opts.ApprovalManager,
router: mux.NewRouter(),
authenticator: opts.Authenticator,
// username: opts.Username,
// password: opts.Password,
store: opts.Store,
store: opts.Store,
uiDir: opts.UIDir,
}
}

Expand All @@ -93,6 +89,10 @@ func (s *TriggerServer) Start() error {
n.Use(negroni.HandlerFunc(corsHeadersMiddleware))
n.UseHandler(s.router)

// if s.uiDir != "" {
// n.Use(negroni.NewStatic(http.Dir(s.uiDir)))
// }

s.server = &http.Server{
Addr: fmt.Sprintf(":%d", s.port),
Handler: n,
Expand Down Expand Up @@ -153,8 +153,22 @@ func (s *TriggerServer) registerRoutes(mux *mux.Router) {

// tracked images
mux.HandleFunc("/v1/tracked", s.requireAdminAuthorization(s.trackedHandler)).Methods("GET", "OPTIONS")
mux.HandleFunc("/v1/tracked", s.requireAdminAuthorization(s.trackSetHandler)).Methods("PUT", "OPTIONS")

// status
mux.HandleFunc("/v1/audit", s.requireAdminAuthorization(s.adminAuditLogHandler)).Methods("GET", "OPTIONS")
mux.HandleFunc("/v1/stats", s.requireAdminAuthorization(s.statsHandler)).Methods("GET", "OPTIONS")

if s.uiDir != "" {
// Serve static assets directly.
mux.PathPrefix("/css/").Handler(http.FileServer(http.Dir(s.uiDir)))
mux.PathPrefix("/assets/").Handler(http.FileServer(http.Dir(s.uiDir)))
mux.PathPrefix("/js/").Handler(http.FileServer(http.Dir(s.uiDir)))
mux.PathPrefix("/img/").Handler(http.FileServer(http.Dir(s.uiDir)))
mux.PathPrefix("/loading/").Handler(http.FileServer(http.Dir(s.uiDir)))

mux.PathPrefix("/").HandlerFunc(indexHandler(s.uiDir))
}
} else {
log.Info("authentication is not enabled, admin HTTP handlers are not initialized")
}
Expand Down Expand Up @@ -284,3 +298,11 @@ func (s *TriggerServer) userInfoHandler(resp http.ResponseWriter, req *http.Requ
type APIResponse struct {
Status string `json:"status"`
}

func indexHandler(uiDir string) func(w http.ResponseWriter, r *http.Request) {
fn := func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, uiDir+"/index.html")
}

return http.HandlerFunc(fn)
}
80 changes: 79 additions & 1 deletion pkg/http/tracked_endpoint.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package http

import "net/http"
import (
"encoding/json"
"fmt"
"net/http"
"time"

"github.com/keel-hq/keel/types"
)

type trackedImage struct {
Image string `json:"image"`
Expand Down Expand Up @@ -31,3 +38,74 @@ func (s *TriggerServer) trackedHandler(resp http.ResponseWriter, req *http.Reque

response(&imgs, 200, err, resp, req)
}

type trackRequest struct {
Provider string `json:"provider"`
Identifier string `json:"identifier"`
Trigger string `json:"trigger"`
Schedule string `json:"schedule"`
}

func (s *TriggerServer) trackSetHandler(resp http.ResponseWriter, req *http.Request) {

var trackReq trackRequest
dec := json.NewDecoder(req.Body)
defer req.Body.Close()

err := dec.Decode(&trackReq)
if err != nil {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(resp, "%s", err)
return
}

switch trackReq.Provider {
case types.ProviderTypeKubernetes.String():
// ok
default:
http.Error(resp, "unsupported provider, supported: 'kubernetes'", http.StatusBadRequest)
return
}

switch trackReq.Trigger {
case "default", "poll":
// ok
default:
http.Error(resp, "unknown trigger type, supported: 'default', 'poll'", http.StatusBadRequest)
return
}

if trackReq.Schedule != "" {
_, err = time.ParseDuration(trackReq.Schedule)
if err != nil {
resp.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(resp, "%s", err)
return
}
} else {
trackReq.Schedule = types.KeelPollDefaultSchedule
}

for _, v := range s.grc.Values() {
if v.Identifier == trackReq.Identifier {

labels := v.GetLabels()
delete(labels, types.KeelTriggerLabel)
v.SetLabels(labels)

ann := v.GetAnnotations()
ann[types.KeelTriggerLabel] = trackReq.Trigger
ann[types.KeelPollScheduleAnnotation] = trackReq.Schedule

v.SetAnnotations(ann)

err := s.kubernetesClient.Update(v)

response(&APIResponse{Status: "updated"}, 200, err, resp, req)
return
}
}

resp.WriteHeader(http.StatusNotFound)
fmt.Fprintf(resp, "resource with identifier '%s' not found", trackReq.Identifier)
}
9 changes: 0 additions & 9 deletions pkg/store/sql/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (

"github.com/google/uuid"
"github.com/keel-hq/keel/types"

log "github.com/sirupsen/logrus"
)

// CreateAuditLog - create new audit log entry
Expand Down Expand Up @@ -123,21 +121,18 @@ func (s *SQLStore) AuditStatistics(query *types.AuditLogStatsQuery) ([]types.Aud
}

for _, l := range logs {
fmt.Println(l.Action)
key := getTime(l.CreatedAt)
switch l.Action {
case types.NotificationDeploymentUpdate.String(), types.NotificationReleaseUpdate.String():
entry, ok := days[key]
if !ok {
log.Errorf("day %s not found", key)
days[key] = types.AuditLogStats{
Updates: 1,
}
}
entry.Updates = entry.Updates + 1
days[key] = entry
case types.AuditActionApprovalApproved:
fmt.Println("approved found")
entry := days[key]
entry.Approved++
days[key] = entry
Expand All @@ -155,10 +150,6 @@ func (s *SQLStore) AuditStatistics(query *types.AuditLogStatsQuery) ([]types.Aud
stats = append(stats, v)
}

for _, s := range stats {
fmt.Println(s.Date)
}

return stats, err

}

0 comments on commit 3657453

Please sign in to comment.