github.com/nais/knorten@v0.0.0-20240104110906-55926958e361/pkg/database/services.go (about)

     1  package database
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/nais/knorten/pkg/database/gensql"
    10  	"golang.org/x/exp/slices"
    11  )
    12  
    13  type AppService struct {
    14  	App     string
    15  	Ingress string
    16  	Slug    string
    17  }
    18  
    19  type TeamServices struct {
    20  	TeamID     string
    21  	Slug       string
    22  	Jupyterhub *AppService
    23  	Airflow    *AppService
    24  	Events     []EventWithLogs
    25  }
    26  
    27  type UserServices struct {
    28  	Services   []TeamServices
    29  	Compute    *gensql.ComputeInstance
    30  	UserGSM    *gensql.UserGoogleSecretManager
    31  	UserEvents []EventWithLogs
    32  }
    33  
    34  func createIngress(team string, chartType gensql.ChartType) string {
    35  	switch chartType {
    36  	case gensql.ChartTypeJupyterhub:
    37  		return fmt.Sprintf("https://%v.jupyter.knada.io", team)
    38  	case gensql.ChartTypeAirflow:
    39  		return fmt.Sprintf("https://%v.airflow.knada.io", team)
    40  	}
    41  
    42  	return ""
    43  }
    44  
    45  func createAppService(slug string, chartType gensql.ChartType) *AppService {
    46  	return &AppService{
    47  		App:     string(chartType),
    48  		Ingress: createIngress(slug, chartType),
    49  		Slug:    slug,
    50  	}
    51  }
    52  
    53  func (r *Repo) ChartsForTeamGet(ctx context.Context, teamID string) ([]gensql.ChartType, error) {
    54  	return r.querier.ChartsForTeamGet(ctx, teamID)
    55  }
    56  
    57  func (r *Repo) ChartDelete(ctx context.Context, teamID string, chartType gensql.ChartType) error {
    58  	return r.querier.ChartDelete(ctx, gensql.ChartDeleteParams{
    59  		TeamID:    teamID,
    60  		ChartType: chartType,
    61  	})
    62  }
    63  
    64  func (r *Repo) ServicesForUser(ctx context.Context, email string) (UserServices, error) {
    65  	teamsForUser, err := r.querier.TeamsForUserGet(ctx, email)
    66  	if err != nil {
    67  		return UserServices{}, err
    68  	}
    69  
    70  	slices.SortFunc(teamsForUser, func(a, b gensql.TeamsForUserGetRow) int {
    71  		if a.ID < b.ID {
    72  			return -1
    73  		} else if a.ID > b.ID {
    74  			return 1
    75  		} else {
    76  			return 0
    77  		}
    78  	})
    79  
    80  	var userServices UserServices
    81  	for _, team := range teamsForUser {
    82  		apps, err := r.querier.ChartsForTeamGet(ctx, team.ID)
    83  		if err != nil {
    84  			return UserServices{}, err
    85  		}
    86  
    87  		events, err := r.EventLogsForOwnerGet(ctx, team.ID, 3)
    88  		if err != nil {
    89  			return UserServices{}, err
    90  		}
    91  
    92  		teamServices := TeamServices{
    93  			TeamID: team.ID,
    94  			Slug:   team.Slug,
    95  			Events: events,
    96  		}
    97  
    98  		for _, app := range apps {
    99  			switch app {
   100  			case gensql.ChartTypeJupyterhub:
   101  				teamServices.Jupyterhub = createAppService(team.Slug, app)
   102  			case gensql.ChartTypeAirflow:
   103  				teamServices.Airflow = createAppService(team.Slug, app)
   104  			}
   105  		}
   106  
   107  		userServices.Services = append(userServices.Services, teamServices)
   108  	}
   109  
   110  	var hasUserServices bool
   111  	compute, err := r.querier.ComputeInstanceGet(ctx, email)
   112  	if err != nil {
   113  		if !errors.Is(err, sql.ErrNoRows) {
   114  			return UserServices{}, err
   115  		}
   116  	} else {
   117  		userServices.Compute = &compute
   118  		hasUserServices = true
   119  	}
   120  
   121  	manager, err := r.querier.UserGoogleSecretManagerGet(ctx, email)
   122  	if err != nil {
   123  		if !errors.Is(err, sql.ErrNoRows) {
   124  			return UserServices{}, err
   125  		}
   126  	} else {
   127  		userServices.UserGSM = &manager
   128  		hasUserServices = true
   129  	}
   130  
   131  	if hasUserServices {
   132  		events, err := r.EventLogsForOwnerGet(ctx, email, 3)
   133  		if err != nil {
   134  			return UserServices{}, err
   135  		}
   136  
   137  		userServices.UserEvents = events
   138  	}
   139  
   140  	return userServices, nil
   141  }
   142  
   143  func (r *Repo) TeamValueInsert(ctx context.Context, chartType gensql.ChartType, key, value, teamID string) error {
   144  	return r.querier.TeamValueInsert(ctx, gensql.TeamValueInsertParams{
   145  		Key:       key,
   146  		Value:     value,
   147  		TeamID:    teamID,
   148  		ChartType: chartType,
   149  	})
   150  }
   151  
   152  func (r *Repo) HelmChartValuesInsert(ctx context.Context, chartType gensql.ChartType, chartValues map[string]string, teamID string) error {
   153  	tx, err := r.db.Begin()
   154  	if err != nil {
   155  		return err
   156  	}
   157  
   158  	querier := r.querier.WithTx(tx)
   159  	for key, value := range chartValues {
   160  		err := querier.TeamValueInsert(ctx, gensql.TeamValueInsertParams{
   161  			Key:       key,
   162  			Value:     value,
   163  			TeamID:    teamID,
   164  			ChartType: chartType,
   165  		})
   166  		if err != nil {
   167  			if err := tx.Rollback(); err != nil {
   168  				r.log.WithError(err).Error("rolling back service create transaction - team chart value insert")
   169  			}
   170  			return err
   171  		}
   172  	}
   173  
   174  	if err := tx.Commit(); err != nil {
   175  		return err
   176  	}
   177  	return nil
   178  }