Files
teleport/integrations/event-handler/state.go
T
Tiago Silva 3e57dde50d GCI: Add special rules for integrations (#40466)
This PR adds a special group (last one) to match the `terraform` and
`event-handler` integrations.

These two integrations aren't imported by teleport codebase but they
import teleport packages. The issue arrises from the fact that they have
their own module namespace. In order to distinguish their module
namespace, this PR proposes moving them into a new (last) import group
and keep Teleport into a separate group. Unfortunately, at the time of
writing `gci` doesn't support skip directories which causes problems for
our `lint` CI step as it will fail.

This results in the following structure for files within the two
integrations:

- standard
- default
- teleport
- specific integration

Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>
2024-04-12 08:44:21 +00:00

228 lines
5.1 KiB
Go

/*
Copyright 2015-2021 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"encoding/binary"
"net"
"os"
"path"
"strings"
"time"
"github.com/gravitational/trace"
"github.com/peterbourgon/diskv/v3"
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/event-handler/lib"
)
const (
// cacheSizeMaxBytes max memory cache
cacheSizeMaxBytes = 1024
// startTimeName is the start time variable name
startTimeName = "start_time"
// cursorName is the cursor variable name
cursorName = "cursor"
// idName is the id variable name
idName = "id"
// sessionPrefix is the session key prefix
sessionPrefix = "session"
// storageDirPerms is storage directory permissions when created
storageDirPerms = 0755
)
// State manages the plugin persistent state. It is stored on disk as a simple key-value database.
type State struct {
// dv is a diskv instance
dv *diskv.Diskv
}
// NewCursor creates new cursor instance
func NewState(c *StartCmdConfig) (*State, error) {
// Simplest transform function: put all the data files into the base dir.
flatTransform := func(s string) []string { return []string{} }
dir, err := createStorageDir(c)
if err != nil {
return nil, trace.Wrap(err)
}
dv := diskv.New(diskv.Options{
BasePath: dir,
Transform: flatTransform,
CacheSizeMax: cacheSizeMaxBytes,
})
s := State{dv}
return &s, nil
}
// createStorageDir is used to calculate storage dir path and create dir if it does not exits
func createStorageDir(c *StartCmdConfig) (string, error) {
log := logger.Standard()
host, port, err := net.SplitHostPort(c.TeleportAddr)
if err != nil {
return "", trace.Wrap(err)
}
dir := strings.TrimSpace(host + "_" + port)
if dir == "_" {
return "", trace.Errorf("Can not generate cursor name from Teleport host %s", c.TeleportAddr)
}
if c.DryRun {
rs, err := lib.RandomString(32)
if err != nil {
return "", trace.Wrap(err)
}
dir = path.Join(dir, "dry_run", rs)
}
dir = path.Join(c.StorageDir, dir)
_, err = os.Stat(dir)
if os.IsNotExist(err) {
err = os.MkdirAll(dir, storageDirPerms)
if err != nil {
return "", trace.Errorf("Can not create storage directory %v : %w", dir, err)
}
log.WithField("dir", dir).Info("Created storage directory")
} else {
log.WithField("dir", dir).Info("Using existing storage directory")
}
return dir, nil
}
// GetStartTime gets current start time
func (s *State) GetStartTime() (*time.Time, error) {
if !s.dv.Has(startTimeName) {
return nil, nil
}
b, err := s.dv.Read(startTimeName)
if err != nil {
return nil, trace.Wrap(err)
}
// No previous start time exist
if string(b) == "" {
return nil, nil
}
t, err := time.Parse(time.RFC3339, string(b))
if err != nil {
return nil, trace.Wrap(err)
}
t = t.Truncate(time.Second)
return &t, nil
}
// SetStartTime sets current start time
func (s *State) SetStartTime(t *time.Time) error {
if t == nil {
return s.dv.Write(startTimeName, []byte(""))
}
v := t.Truncate(time.Second).Format(time.RFC3339)
return s.dv.Write(startTimeName, []byte(v))
}
// GetCursor gets current cursor value
func (s *State) GetCursor() (string, error) {
return s.getStringValue(cursorName)
}
// SetCursor sets cursor value
func (s *State) SetCursor(v string) error {
return s.setStringValue(cursorName, v)
}
// GetID gets current ID value
func (s *State) GetID() (string, error) {
return s.getStringValue(idName)
}
// SetID sets cursor value
func (s *State) SetID(v string) error {
return s.setStringValue(idName, v)
}
// getStringValue gets a string value
func (s *State) getStringValue(name string) (string, error) {
if !s.dv.Has(name) {
return "", nil
}
b, err := s.dv.Read(name)
if err != nil {
return "", trace.Wrap(err)
}
return string(b), err
}
// setStringValue sets string value
func (s *State) setStringValue(name string, value string) error {
err := s.dv.Write(name, []byte(value))
return trace.Wrap(err)
}
// GetSessions get active sessions (map[id]index)
func (s *State) GetSessions() (map[string]int64, error) {
r := make(map[string]int64)
for key := range s.dv.KeysPrefix(sessionPrefix, nil) {
b, err := s.dv.Read(key)
if err != nil {
return nil, trace.Wrap(err)
}
id := key[len(sessionPrefix):]
r[id] = int64(binary.BigEndian.Uint64(b))
}
return r, nil
}
// SetSessionIndex writes current session index into state
func (s *State) SetSessionIndex(id string, index int64) error {
var b = make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(index))
return s.dv.Write(sessionPrefix+id, b)
}
// RemoveSession removes session from the state
func (s *State) RemoveSession(id string) error {
return s.dv.Erase(sessionPrefix + id)
}