mirror of
https://github.com/paralus/paralus.git
synced 2026-05-08 17:36:56 +00:00
This was done inorder to support transactions which will be done in the next PR. This is the first step towards that.
454 lines
15 KiB
Go
454 lines
15 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/RafaySystems/rcloud-base/internal/dao"
|
|
"github.com/RafaySystems/rcloud-base/internal/models"
|
|
"github.com/RafaySystems/rcloud-base/internal/persistence/provider/pg"
|
|
"github.com/RafaySystems/rcloud-base/pkg/converter"
|
|
"github.com/RafaySystems/rcloud-base/pkg/query"
|
|
"github.com/RafaySystems/rcloud-base/pkg/sentry/cryptoutil"
|
|
commonv3 "github.com/RafaySystems/rcloud-base/proto/types/commonpb/v3"
|
|
"github.com/RafaySystems/rcloud-base/proto/types/sentry"
|
|
"github.com/google/uuid"
|
|
"github.com/uptrace/bun"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
var KEKFunc cryptoutil.PasswordFunc
|
|
|
|
// BootstrapService is the interface for bootstrap operations
|
|
type BootstrapService interface {
|
|
// bootstrap infra methods
|
|
PatchBootstrapInfra(ctx context.Context, infra *sentry.BootstrapInfra) error
|
|
GetBootstrapInfra(ctx context.Context, name string) (*sentry.BootstrapInfra, error)
|
|
// bootstrap template methods
|
|
PatchBootstrapAgentTemplate(ctx context.Context, template *sentry.BootstrapAgentTemplate) error
|
|
GetBootstrapAgentTemplate(ctx context.Context, name string) (*sentry.BootstrapAgentTemplate, error)
|
|
GetBootstrapAgentTemplateForToken(ctx context.Context, token string) (*sentry.BootstrapAgentTemplate, error)
|
|
GetBootstrapAgentTemplateForHost(ctx context.Context, host string) (*sentry.BootstrapAgentTemplate, error)
|
|
SelectBootstrapAgentTemplates(ctx context.Context, opts ...query.Option) (*sentry.BootstrapAgentTemplateList, error)
|
|
// bootstrap agent methods
|
|
CreateBootstrapAgent(ctx context.Context, agent *sentry.BootstrapAgent) error
|
|
GetBootstrapAgent(ctx context.Context, templateRef string, opts ...query.Option) (*sentry.BootstrapAgent, error)
|
|
GetBootstrapAgents(ctx context.Context, templateRef string, opts ...query.Option) (*sentry.BootstrapAgentList, error)
|
|
GetBootstrapAgentForToken(ctx context.Context, token string) (*sentry.BootstrapAgent, error)
|
|
GetBootstrapAgentCountForClusterID(ctx context.Context, clusterID string, orgID string) (int, error)
|
|
GetBootstrapAgentForClusterID(ctx context.Context, clusterID string, orgID string) (*sentry.BootstrapAgent, error)
|
|
SelectBootstrapAgents(ctx context.Context, templateRef string, opts ...query.Option) (*sentry.BootstrapAgentList, error)
|
|
RegisterBootstrapAgent(ctx context.Context, token string) error
|
|
DeleteBootstrapAgent(ctx context.Context, templateRef string, opts ...query.Option) error
|
|
PatchBootstrapAgent(ctx context.Context, ba *sentry.BootstrapAgent, templateRef string, opts ...query.Option) error
|
|
}
|
|
|
|
// bootstrapService implements BootstrapService
|
|
type bootstrapService struct {
|
|
db *bun.DB
|
|
}
|
|
|
|
// NewBootstrapService return new bootstrap service
|
|
func NewBootstrapService(db *bun.DB) BootstrapService {
|
|
return &bootstrapService{db}
|
|
}
|
|
|
|
func (s *bootstrapService) PatchBootstrapInfra(ctx context.Context, infra *sentry.BootstrapInfra) error {
|
|
return dao.CreateOrUpdateBootstrapInfra(ctx, s.db, convertToInfraModel(infra))
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapInfra(ctx context.Context, name string) (*sentry.BootstrapInfra, error) {
|
|
|
|
var bi models.BootstrapInfra
|
|
_, err := pg.GetByName(ctx, s.db, name, &bi)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return prepareInfraResponse(&bi), nil
|
|
}
|
|
|
|
func (s *bootstrapService) PatchBootstrapAgentTemplate(ctx context.Context, template *sentry.BootstrapAgentTemplate) error {
|
|
templ := models.BootstrapAgentTemplate{
|
|
Name: template.Metadata.Name,
|
|
DisplayName: template.Metadata.DisplayName,
|
|
InfraRef: template.Spec.InfraRef,
|
|
ModifiedAt: time.Now(),
|
|
Labels: converter.ConvertToJsonRawMessage(template.Metadata.Labels),
|
|
Annotations: converter.ConvertToJsonRawMessage(template.Metadata.Annotations),
|
|
AutoRegister: template.Spec.AutoRegister,
|
|
AutoApprove: template.Spec.AutoApprove,
|
|
TemplateType: sentry.BootstrapAgentTemplateType_name[int32(template.Spec.TemplateType)],
|
|
IgnoreMultipleRegister: template.Spec.IgnoreMultipleRegister,
|
|
InclusterTemplate: template.Spec.InClusterTemplate,
|
|
OutofclusterTemplate: template.Spec.OutOfClusterTemplate,
|
|
Token: template.Spec.Token,
|
|
Hosts: converter.ConvertToJsonRawMessage(template.Spec.Hosts),
|
|
CreatedAt: time.Now(),
|
|
}
|
|
|
|
return dao.CreateOrUpdateBootstrapAgentTemplate(ctx, s.db, &templ)
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgentTemplate(ctx context.Context, agentType string) (*sentry.BootstrapAgentTemplate, error) {
|
|
var template models.BootstrapAgentTemplate
|
|
_, err := pg.GetByName(ctx, s.db, agentType, &template)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return prepareTemplateResponse(&template), nil
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgentTemplateForToken(ctx context.Context, token string) (*sentry.BootstrapAgentTemplate, error) {
|
|
bat, err := dao.GetBootstrapAgentTemplateForToken(ctx, s.db, token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return prepareTemplateResponse(bat), nil
|
|
}
|
|
|
|
func (s *bootstrapService) SelectBootstrapAgentTemplates(ctx context.Context, opts ...query.Option) (*sentry.BootstrapAgentTemplateList, error) {
|
|
queryOptions := &commonv3.QueryOptions{}
|
|
for _, opt := range opts {
|
|
opt(queryOptions)
|
|
}
|
|
|
|
batl, count, err := dao.SelectBootstrapAgentTemplates(ctx, s.db, queryOptions)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := &sentry.BootstrapAgentTemplateList{Metadata: &commonv3.ListMetadata{
|
|
Count: int64(count),
|
|
}}
|
|
for _, bat := range batl {
|
|
ret.Items = append(ret.Items, prepareTemplateResponse(&bat))
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func (s *bootstrapService) CreateBootstrapAgent(ctx context.Context, agent *sentry.BootstrapAgent) error {
|
|
ba := convertToAgentModel(agent)
|
|
ba.CreatedAt = time.Now()
|
|
return dao.CreateBootstrapAgent(ctx, s.db, ba)
|
|
}
|
|
|
|
func convertToAgentModel(agent *sentry.BootstrapAgent) *models.BootstrapAgent {
|
|
agentMdl := &models.BootstrapAgent{
|
|
Name: agent.Metadata.Name,
|
|
TemplateRef: agent.Spec.TemplateRef,
|
|
AgentMode: agent.Spec.AgentMode.String(),
|
|
DisplayName: agent.Metadata.DisplayName,
|
|
Labels: converter.ConvertToJsonRawMessage(agent.Metadata.Labels),
|
|
Annotations: converter.ConvertToJsonRawMessage(agent.Metadata.Annotations),
|
|
Token: agent.Spec.Token,
|
|
}
|
|
if orgId, err := uuid.Parse(agent.Metadata.Organization); err == nil {
|
|
agentMdl.OrganizationId = orgId
|
|
}
|
|
if partId, err := uuid.Parse(agent.Metadata.Partner); err == nil {
|
|
agentMdl.PartnerId = partId
|
|
}
|
|
if projId, err := uuid.Parse(agent.Metadata.Project); err == nil {
|
|
agentMdl.ProjectId = projId
|
|
}
|
|
return agentMdl
|
|
}
|
|
|
|
func convertToInfraModel(infra *sentry.BootstrapInfra) *models.BootstrapInfra {
|
|
return &models.BootstrapInfra{
|
|
Name: infra.Metadata.Name,
|
|
ModifiedAt: time.Now(),
|
|
CaCert: infra.Spec.CaCert,
|
|
CaKey: infra.Spec.CaKey,
|
|
DisplayName: infra.Metadata.DisplayName,
|
|
Labels: converter.ConvertToJsonRawMessage(infra.Metadata.Labels),
|
|
Annotations: converter.ConvertToJsonRawMessage(infra.Metadata.Annotations),
|
|
}
|
|
}
|
|
|
|
func prepareAgentResponse(agent *models.BootstrapAgent) *sentry.BootstrapAgent {
|
|
var lbls map[string]string
|
|
if agent.Labels != nil {
|
|
json.Unmarshal(agent.Labels, &lbls)
|
|
}
|
|
var ann map[string]string
|
|
if agent.Annotations != nil {
|
|
json.Unmarshal(agent.Annotations, &ann)
|
|
}
|
|
ba := &sentry.BootstrapAgent{
|
|
Kind: "BootstrapAgent",
|
|
Metadata: &commonv3.Metadata{
|
|
Name: agent.Name,
|
|
DisplayName: agent.DisplayName,
|
|
Description: agent.DisplayName,
|
|
ModifiedAt: timestamppb.New(agent.ModifiedAt),
|
|
Labels: lbls,
|
|
Annotations: ann,
|
|
},
|
|
Spec: &sentry.BootstrapAgentSpec{
|
|
Token: agent.Token,
|
|
TemplateRef: agent.TemplateRef,
|
|
AgentMode: sentry.BootstrapAgentMode(sentry.BootstrapAgentMode_value[agent.AgentMode]),
|
|
},
|
|
Status: &sentry.BootStrapAgentStatus{
|
|
TokenState: sentry.BootstrapAgentState(sentry.BootstrapAgentMode_value[agent.TokenState]),
|
|
IpAddress: agent.IPAddress,
|
|
LastCheckedIn: timestamppb.New(agent.LastCheckedIn),
|
|
Fingerprint: agent.Fingerprint,
|
|
},
|
|
}
|
|
return ba
|
|
}
|
|
|
|
func prepareInfraResponse(infra *models.BootstrapInfra) *sentry.BootstrapInfra {
|
|
var lbls map[string]string
|
|
if infra.Labels != nil {
|
|
json.Unmarshal(infra.Labels, &lbls)
|
|
}
|
|
var ann map[string]string
|
|
if infra.Annotations != nil {
|
|
json.Unmarshal(infra.Annotations, &ann)
|
|
}
|
|
bi := &sentry.BootstrapInfra{
|
|
Kind: "BootstrapInfra",
|
|
Metadata: &commonv3.Metadata{
|
|
Name: infra.Name,
|
|
DisplayName: infra.DisplayName,
|
|
ModifiedAt: timestamppb.New(infra.ModifiedAt),
|
|
Labels: lbls,
|
|
Annotations: ann,
|
|
},
|
|
Spec: &sentry.BootstrapInfraSpec{
|
|
CaCert: infra.CaCert,
|
|
CaKey: infra.CaKey,
|
|
},
|
|
}
|
|
return bi
|
|
}
|
|
|
|
func prepareTemplateResponse(template *models.BootstrapAgentTemplate) *sentry.BootstrapAgentTemplate {
|
|
var lbls map[string]string
|
|
if template.Labels != nil {
|
|
json.Unmarshal(template.Labels, &lbls)
|
|
}
|
|
var ann map[string]string
|
|
if template.Annotations != nil {
|
|
json.Unmarshal(template.Annotations, &ann)
|
|
}
|
|
var hosts []*sentry.BootstrapTemplateHost
|
|
if template.Hosts != nil {
|
|
json.Unmarshal(template.Hosts, &hosts)
|
|
}
|
|
templResp := sentry.BootstrapAgentTemplate{
|
|
Kind: "BootstrapAgentTemplate",
|
|
Metadata: &commonv3.Metadata{
|
|
Name: template.Name,
|
|
DisplayName: template.DisplayName,
|
|
Labels: lbls,
|
|
Annotations: ann,
|
|
ModifiedAt: timestamppb.New(template.ModifiedAt),
|
|
},
|
|
Spec: &sentry.BootstrapAgentTemplateSpec{
|
|
InfraRef: template.InfraRef,
|
|
AutoRegister: template.AutoRegister,
|
|
AutoApprove: template.AutoApprove,
|
|
IgnoreMultipleRegister: template.IgnoreMultipleRegister,
|
|
TemplateType: sentry.BootstrapAgentTemplateType(sentry.BootstrapAgentTemplateType_value[template.TemplateType]),
|
|
Token: template.Token,
|
|
Hosts: hosts,
|
|
InClusterTemplate: template.InclusterTemplate,
|
|
OutOfClusterTemplate: template.OutofclusterTemplate,
|
|
},
|
|
}
|
|
return &templResp
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgents(ctx context.Context, templateRef string, opts ...query.Option) (ret *sentry.BootstrapAgentList, err error) {
|
|
queryOptions := &commonv3.QueryOptions{}
|
|
for _, opt := range opts {
|
|
opt(queryOptions)
|
|
}
|
|
|
|
agl, count, err := dao.GetBootstrapAgents(ctx, s.db, queryOptions, templateRef)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret = new(sentry.BootstrapAgentList)
|
|
ret.Metadata = &commonv3.ListMetadata{
|
|
Count: int64(count),
|
|
}
|
|
for _, ag := range agl {
|
|
ret.Items = append(ret.Items, prepareAgentResponse(&ag))
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgent(ctx context.Context, templateRef string, opts ...query.Option) (*sentry.BootstrapAgent, error) {
|
|
queryOptions := &commonv3.QueryOptions{}
|
|
for _, opt := range opts {
|
|
opt(queryOptions)
|
|
}
|
|
ba, err := dao.GetBootstrapAgent(ctx, s.db, templateRef, queryOptions)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return prepareAgentResponse(ba), nil
|
|
}
|
|
|
|
func (s *bootstrapService) SelectBootstrapAgents(ctx context.Context, templateRef string, opts ...query.Option) (ret *sentry.BootstrapAgentList, err error) {
|
|
queryOptions := &commonv3.QueryOptions{}
|
|
for _, opt := range opts {
|
|
opt(queryOptions)
|
|
}
|
|
|
|
agl, count, err := dao.SelectBootstrapAgents(ctx, s.db, templateRef, queryOptions)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret = new(sentry.BootstrapAgentList)
|
|
ret.Metadata = &commonv3.ListMetadata{
|
|
Count: int64(count),
|
|
}
|
|
for _, ag := range agl {
|
|
ret.Items = append(ret.Items, prepareAgentResponse(&ag))
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (s *bootstrapService) RegisterBootstrapAgent(ctx context.Context, token string) error {
|
|
err := s.db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
|
|
return dao.RegisterBootstrapAgent(ctx, tx, token)
|
|
})
|
|
return err
|
|
}
|
|
|
|
func (s *bootstrapService) DeleteBootstrapAgent(ctx context.Context, templateRef string, opts ...query.Option) error {
|
|
queryOptions := &commonv3.QueryOptions{}
|
|
for _, opt := range opts {
|
|
opt(queryOptions)
|
|
}
|
|
|
|
err := dao.DeleteBootstrapAgent(ctx, s.db, templateRef, queryOptions)
|
|
return err
|
|
}
|
|
|
|
func (s *bootstrapService) PatchBootstrapAgent(ctx context.Context, ba *sentry.BootstrapAgent, templateRef string, opts ...query.Option) error {
|
|
|
|
queryOptions := &commonv3.QueryOptions{}
|
|
for _, opt := range opts {
|
|
opt(queryOptions)
|
|
}
|
|
|
|
err := s.db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
|
|
bdb, err := dao.GetBootstrapAgent(ctx, s.db, templateRef, queryOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if bdb.TokenState > sentry.BootstrapAgentState_NotSet.String() {
|
|
bdb.TokenState = ba.Status.TokenState.String()
|
|
}
|
|
if ba.Status != nil {
|
|
if ba.Status.IpAddress != "" {
|
|
bdb.IPAddress = ba.Status.IpAddress
|
|
} else {
|
|
bdb.IPAddress = ""
|
|
}
|
|
if !ba.Status.LastCheckedIn.AsTime().IsZero() {
|
|
bdb.LastCheckedIn = ba.Status.LastCheckedIn.AsTime()
|
|
}
|
|
if ba.Status.Fingerprint != "" {
|
|
bdb.Fingerprint = ba.Status.Fingerprint
|
|
} else {
|
|
bdb.Fingerprint = ""
|
|
}
|
|
}
|
|
bdb.ModifiedAt = time.Now()
|
|
bdb.DisplayName = ba.Metadata.DisplayName
|
|
return dao.UpdateBootstrapAgent(ctx, s.db, bdb, queryOptions)
|
|
})
|
|
return err
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgentForToken(ctx context.Context, token string) (*sentry.BootstrapAgent, error) {
|
|
ba, err := dao.GetBootstrapAgentForToken(ctx, s.db, token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return prepareAgentResponse(ba), nil
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgentTemplateForHost(ctx context.Context, host string) (*sentry.BootstrapAgentTemplate, error) {
|
|
bat, err := dao.GetBootstrapAgentTemplateForHost(ctx, s.db, host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return prepareTemplateResponse(bat), nil
|
|
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgentCountForClusterID(ctx context.Context, clusterID string, orgID string) (int, error) {
|
|
count, err := dao.GetBootstrapAgentCountForClusterID(ctx, s.db, clusterID, uuid.MustParse(orgID))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if count <= 0 {
|
|
return 0, fmt.Errorf("invalid request")
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
func (s *bootstrapService) GetBootstrapAgentForClusterID(ctx context.Context, clusterID string, orgID string) (*sentry.BootstrapAgent, error) {
|
|
ba, err := dao.GetBootstrapAgentForClusterID(ctx, s.db, clusterID, uuid.MustParse(orgID))
|
|
if err != nil || ba == nil {
|
|
return nil, err
|
|
}
|
|
return prepareAgentResponse(ba), nil
|
|
}
|
|
|
|
func (s *bootstrapService) GetRelayAgent(ctx context.Context, ClusterScope string, opts ...query.Option) (*sentry.BootstrapAgent, error) {
|
|
queryOptions := &commonv3.QueryOptions{}
|
|
for _, opt := range opts {
|
|
opt(queryOptions)
|
|
}
|
|
|
|
bal, err := s.SelectBootstrapAgents(ctx, queryOptions.Name,
|
|
query.WithOrganizationID(queryOptions.Organization),
|
|
query.WithPartnerID(queryOptions.Partner),
|
|
)
|
|
if err != nil {
|
|
_log.Infow("failed to get default bootstrap agent list", "cluster", ClusterScope, "error", err)
|
|
return nil, err
|
|
}
|
|
|
|
if bal != nil && bal.Metadata.Count > 0 {
|
|
var ba sentry.BootstrapAgent
|
|
found := false
|
|
// match labels
|
|
for _, b := range bal.Items {
|
|
_log.Infow("match", "ClusterScope", ClusterScope, "DisplayName", b.Metadata.DisplayName)
|
|
if "cluster/"+b.Metadata.DisplayName == ClusterScope {
|
|
found = true
|
|
ba = *b
|
|
break
|
|
}
|
|
}
|
|
if found {
|
|
// found bootstrap relay agent for cluster as per the association
|
|
return &ba, nil
|
|
} else {
|
|
_log.Infow("did not find relay bootstrap agent for", "cluster", ClusterScope, "template", queryOptions.Name)
|
|
}
|
|
}
|
|
_log.Infow("did not find relay bootstrap agent for", "cluster", ClusterScope, "template", queryOptions.Name)
|
|
return nil, fmt.Errorf("failed to get relay agent")
|
|
}
|