github.com/esnet/gdg@v0.6.1-0.20240412190737-6b6eba9c14d8/internal/service/connection_permissions.go (about)

     1  package service
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"log"
     7  	"log/slog"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/esnet/gdg/internal/config"
    12  	"github.com/esnet/gdg/internal/service/filters"
    13  	"github.com/esnet/gdg/internal/tools"
    14  	"github.com/gosimple/slug"
    15  	"github.com/grafana/grafana-openapi-client-go/client/datasource_permissions"
    16  	"github.com/grafana/grafana-openapi-client-go/models"
    17  )
    18  
    19  // ListConnectionPermissions lists all connection permission matching the given filter
    20  func (s *DashNGoImpl) ListConnectionPermissions(filter filters.Filter) map[*models.DataSourceListItemDTO]*models.DataSourcePermissionsDTO {
    21  	if !s.grafanaConf.IsEnterprise() {
    22  		log.Fatal("Requires Enterprise to be enabled.  Please check your GDG configuration and try again")
    23  	}
    24  	result := make(map[*models.DataSourceListItemDTO]*models.DataSourcePermissionsDTO)
    25  	connections := s.ListConnections(filter)
    26  	for ndx, connection := range connections {
    27  		permission, err := s.getConnectionPermission(connection.ID)
    28  		if err != nil {
    29  			slog.Error("unable to retrieve connection permissions for ID", "id", connection.ID)
    30  			continue
    31  		}
    32  		result[&connections[ndx]] = permission.GetPayload()
    33  
    34  	}
    35  
    36  	return result
    37  }
    38  
    39  // DownloadConnectionPermissions download permissions to local file system
    40  func (s *DashNGoImpl) DownloadConnectionPermissions(filter filters.Filter) []string {
    41  	slog.Info("Downloading connection permissions")
    42  	var (
    43  		dsPacked  []byte
    44  		err       error
    45  		dataFiles []string
    46  	)
    47  	currentPermissions := s.ListConnectionPermissions(filter)
    48  	for connection, permission := range currentPermissions {
    49  		if dsPacked, err = json.MarshalIndent(permission, "", "	"); err != nil {
    50  			slog.Error("unable to marshall json ", "err", err.Error(), "connectionName", connection.Name)
    51  			continue
    52  		}
    53  		dsPath := buildResourcePath(slug.Make(connection.Name), config.ConnectionPermissionResource)
    54  		if err = s.storage.WriteFile(dsPath, dsPacked); err != nil {
    55  			slog.Error("unable to write file. ", "filename", slug.Make(connection.Name), "error", err.Error())
    56  		} else {
    57  			dataFiles = append(dataFiles, dsPath)
    58  		}
    59  	}
    60  	return dataFiles
    61  }
    62  
    63  // UploadConnectionPermissions upload connection permissions
    64  func (s *DashNGoImpl) UploadConnectionPermissions(filter filters.Filter) []string {
    65  	var (
    66  		rawFolder []byte
    67  		dataFiles []string
    68  	)
    69  	if !s.grafanaConf.IsEnterprise() {
    70  		log.Fatal("Requires Enterprise to be enabled.  Please check your GDG configuration and try again")
    71  	}
    72  
    73  	filesInDir, err := s.storage.FindAllFiles(config.Config().GetDefaultGrafanaConfig().GetPath(config.ConnectionPermissionResource), false)
    74  	if err != nil {
    75  		log.Fatalf("Failed to read folders permission imports: %s", err.Error())
    76  	}
    77  	for _, file := range filesInDir {
    78  		fileLocation := filepath.Join(config.Config().GetDefaultGrafanaConfig().GetPath(config.ConnectionPermissionResource), file)
    79  		if !filter.ValidateAll(map[filters.FilterType]string{filters.Name: strings.ReplaceAll(file, ".json", "")}) {
    80  			slog.Debug("File does not match pattern, skipping file", "filename", file)
    81  			continue
    82  		}
    83  		if strings.HasSuffix(file, ".json") {
    84  			if rawFolder, err = s.storage.ReadFile(fileLocation); err != nil {
    85  				slog.Error("failed to read file %s", "filename", fileLocation, "err", err)
    86  				continue
    87  			}
    88  		}
    89  
    90  		newEntries := new(models.DataSourcePermissionsDTO)
    91  		err = json.Unmarshal(rawFolder, &newEntries)
    92  		if err != nil {
    93  			slog.Warn("Failed to Decode payload for file", "filename", fileLocation)
    94  			continue
    95  		}
    96  		// Get current permissions
    97  		permissions, err := s.getConnectionPermission(newEntries.DatasourceID)
    98  		if err != nil {
    99  			slog.Error("connection permission could not be retrieved, cannot update permissions")
   100  			continue
   101  		}
   102  
   103  		success := true
   104  		// Delete datasource Permissions
   105  		for _, p := range permissions.GetPayload().Permissions {
   106  			success = s.deleteConnectionPermission(p.ID, newEntries.DatasourceID)
   107  		}
   108  
   109  		if !success {
   110  			slog.Error("Failed to delete previous data, cannot update permissions")
   111  			continue
   112  		}
   113  
   114  		for _, entry := range newEntries.Permissions {
   115  			p := datasource_permissions.NewAddPermissionParams()
   116  			p.SetUserID(tools.PtrOf(entry.UserID))
   117  			p.SetDatasourceID(fmt.Sprintf("%d", entry.DatasourceID))
   118  			p.SetTeamID(tools.PtrOf(entry.TeamID))
   119  			p.SetPermission(tools.PtrOf(int64(entry.Permission)))
   120  			if entry.BuiltInRole != "" {
   121  				p.SetBuiltinRole(tools.PtrOf(entry.BuiltInRole))
   122  			}
   123  			_, err = s.GetClient().DatasourcePermissions.AddPermission(p)
   124  			if err != nil {
   125  				slog.Error("Failed to update folder permissions")
   126  			} else {
   127  				dataFiles = append(dataFiles, fileLocation)
   128  			}
   129  		}
   130  	}
   131  
   132  	slog.Info("Removing all previous permissions and re-applying")
   133  	return dataFiles
   134  }
   135  
   136  // DeleteAllConnectionPermissions clear all non-default permissions from all connections
   137  func (s *DashNGoImpl) DeleteAllConnectionPermissions(filter filters.Filter) []string {
   138  	dataSources := make([]string, 0)
   139  	connectionPermissions := s.ListConnectionPermissions(filter)
   140  	for key, connection := range connectionPermissions {
   141  		success := true
   142  		for _, p := range connection.Permissions {
   143  			res := s.deleteConnectionPermission(p.ID, connection.DatasourceID)
   144  			if !res {
   145  				success = false
   146  			}
   147  		}
   148  		if success {
   149  			dataSources = append(dataSources, key.Name)
   150  		}
   151  	}
   152  
   153  	return dataSources
   154  }
   155  
   156  // deleteConnectionPermission delete a given permission associated with a given datasourceId
   157  func (s *DashNGoImpl) deleteConnectionPermission(permissionId int64, datasourceId int64) bool {
   158  	permissionIdStr := fmt.Sprintf("%d", permissionId)
   159  	connectionId := fmt.Sprintf("%d", datasourceId)
   160  	resp, err := s.GetClient().DatasourcePermissions.DeletePermissions(permissionIdStr, connectionId)
   161  	if err != nil {
   162  		return false
   163  	}
   164  	slog.Debug("permission has been removed associated with datasource %d: %s", "permissionId", permissionId, "datasourceId", datasourceId, "response", resp.GetPayload().Message)
   165  	return true
   166  }
   167  
   168  // getConnectionPermission Get all permissions for a given connection
   169  func (s *DashNGoImpl) getConnectionPermission(id int64) (*datasource_permissions.GetAllPermissionsOK, error) {
   170  	return s.GetClient().DatasourcePermissions.GetAllPermissions(fmt.Sprintf("%d", id))
   171  }