actions-runner-controller/pkg/hookdeliveryforwarder/configmap/checkpointer.go

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/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
}