Files
actions-runner-controller/pkg/hookdeliveryforwarder/configmap/checkpointer.go
Yusuke Kuoka f858e2e432 Add POC of GitHub Webhook Delivery Forwarder (#682)
* Add POC of GitHub Webhook Delivery Forwarder

* multi-forwarder and ctrl-c existing and fix for non-woring http post

* Rename source files

* Extract signal handling into a dedicated source file

* Faster ctrl-c handling

* Enable automatic creation of repo hook on startup

* Add support for forwarding org hook deliveries

* Set hook secret on hook creation via envvar (HOOK_SECRET)

* Fix org hook support

* Fix HOOK_SECRET for consistency

* Refactor to prepare for custom log position provider

* Refactor to extract inmemory log position provider

* Add configmap-based log position provider

* Rename githubwebhookdeliveryforwarder to hookdeliveryforwarder

* Refactor to rename LogPositionProvider to Checkpointer and extract ConfigMap checkpointer into a dedicated pkg

* Refactor to extract logger initialization

* Add hookdeliveryforwarder README and bump go-github to unreleased ver
2021-07-14 10:18:55 +09:00

101 lines
2.0 KiB
Go

package configmap
import (
"context"
"encoding/json"
"fmt"
"time"
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/actions-runner-controller/actions-runner-controller/pkg/hookdeliveryforwarder"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type ConfigMapCheckpointer struct {
Name string
NS string
Client client.Client
}
type state struct {
DeliveredAt time.Time `json:"delivered_at"`
ID int64 `json:"id"`
}
func (p *ConfigMapCheckpointer) GetOrCreate(hookID int64) (*hookdeliveryforwarder.State, error) {
var cm corev1.ConfigMap
if err := p.Client.Get(context.Background(), types.NamespacedName{Namespace: p.NS, Name: p.Name}, &cm); err != nil {
if !kerrors.IsNotFound(err) {
return nil, err
}
cm.Name = p.Name
cm.Namespace = p.NS
if err := p.Client.Create(context.Background(), &cm); err != nil {
return nil, err
}
}
idStr := fmt.Sprintf("hook_%d", hookID)
var unmarshalled state
data, ok := cm.Data[idStr]
if ok {
if err := json.Unmarshal([]byte(data), &unmarshalled); err != nil {
return nil, err
}
}
pos := &hookdeliveryforwarder.State{
DeliveredAt: unmarshalled.DeliveredAt,
ID: unmarshalled.ID,
}
if pos.DeliveredAt.IsZero() {
pos.DeliveredAt = time.Now()
}
return pos, nil
}
func (p *ConfigMapCheckpointer) Update(hookID int64, pos *hookdeliveryforwarder.State) error {
var cm corev1.ConfigMap
if err := p.Client.Get(context.Background(), types.NamespacedName{Namespace: p.NS, Name: p.Name}, &cm); err != nil {
return err
}
var posData state
posData.DeliveredAt = pos.DeliveredAt
posData.ID = pos.ID
idStr := fmt.Sprintf("hook_%d", hookID)
data, err := json.Marshal(posData)
if err != nil {
return err
}
copy := cm.DeepCopy()
if copy.Data == nil {
copy.Data = map[string]string{}
}
copy.Data[idStr] = string(data)
if err := p.Client.Patch(context.Background(), copy, client.MergeFrom(&cm)); err != nil {
return err
}
return nil
}