mirror of https://github.com/portainer/portainer
				
				
				
			feat(snapshots): separate snapshots from endpoint DB struct EE-4099 (#7614)
							parent
							
								
									4fe2a7c750
								
							
						
					
					
						commit
						6e0f83b99e
					
				| 
						 | 
				
			
			@ -40,6 +40,7 @@ type (
 | 
			
		|||
		Role() RoleService
 | 
			
		||||
		APIKeyRepository() APIKeyRepository
 | 
			
		||||
		Settings() SettingsService
 | 
			
		||||
		Snapshot() SnapshotService
 | 
			
		||||
		SSLSettings() SSLSettingsService
 | 
			
		||||
		Stack() StackService
 | 
			
		||||
		Tag() TagService
 | 
			
		||||
| 
						 | 
				
			
			@ -214,6 +215,15 @@ type (
 | 
			
		|||
		BucketName() string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SnapshotService interface {
 | 
			
		||||
		Snapshot(endpointID portainer.EndpointID) (*portainer.Snapshot, error)
 | 
			
		||||
		Snapshots() ([]portainer.Snapshot, error)
 | 
			
		||||
		UpdateSnapshot(snapshot *portainer.Snapshot) error
 | 
			
		||||
		DeleteSnapshot(endpointID portainer.EndpointID) error
 | 
			
		||||
		Create(snapshot *portainer.Snapshot) error
 | 
			
		||||
		BucketName() string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// SSLSettingsService represents a service for managing application settings
 | 
			
		||||
	SSLSettingsService interface {
 | 
			
		||||
		Settings() (*portainer.SSLSettings, error)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
package snapshot
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	BucketName = "snapshots"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Service struct {
 | 
			
		||||
	connection portainer.Connection
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) BucketName() string {
 | 
			
		||||
	return BucketName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewService(connection portainer.Connection) (*Service, error) {
 | 
			
		||||
	err := connection.SetServiceName(BucketName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Service{
 | 
			
		||||
		connection: connection,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) Snapshot(endpointID portainer.EndpointID) (*portainer.Snapshot, error) {
 | 
			
		||||
	var snapshot portainer.Snapshot
 | 
			
		||||
	identifier := service.connection.ConvertToKey(int(endpointID))
 | 
			
		||||
 | 
			
		||||
	err := service.connection.GetObject(BucketName, identifier, &snapshot)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &snapshot, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) Snapshots() ([]portainer.Snapshot, error) {
 | 
			
		||||
	var snapshots = make([]portainer.Snapshot, 0)
 | 
			
		||||
 | 
			
		||||
	err := service.connection.GetAllWithJsoniter(
 | 
			
		||||
		BucketName,
 | 
			
		||||
		&portainer.Snapshot{},
 | 
			
		||||
		func(obj interface{}) (interface{}, error) {
 | 
			
		||||
			snapshot, ok := obj.(*portainer.Snapshot)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				logrus.WithField("obj", obj).Errorf("Failed to convert to Snapshot object")
 | 
			
		||||
				return nil, fmt.Errorf("failed to convert to Snapshot object: %s", obj)
 | 
			
		||||
			}
 | 
			
		||||
			snapshots = append(snapshots, *snapshot)
 | 
			
		||||
			return &portainer.Snapshot{}, nil
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	return snapshots, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) UpdateSnapshot(snapshot *portainer.Snapshot) error {
 | 
			
		||||
	identifier := service.connection.ConvertToKey(int(snapshot.EndpointID))
 | 
			
		||||
	return service.connection.UpdateObject(BucketName, identifier, snapshot)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) DeleteSnapshot(endpointID portainer.EndpointID) error {
 | 
			
		||||
	identifier := service.connection.ConvertToKey(int(endpointID))
 | 
			
		||||
	return service.connection.DeleteObject(BucketName, identifier)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) Create(snapshot *portainer.Snapshot) error {
 | 
			
		||||
	return service.connection.CreateObjectWithId(BucketName, int(snapshot.EndpointID), snapshot)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ func (store *Store) MigrateData() error {
 | 
			
		|||
		RoleService:             store.RoleService,
 | 
			
		||||
		ScheduleService:         store.ScheduleService,
 | 
			
		||||
		SettingsService:         store.SettingsService,
 | 
			
		||||
		SnapshotService:         store.SnapshotService,
 | 
			
		||||
		StackService:            store.StackService,
 | 
			
		||||
		TagService:              store.TagService,
 | 
			
		||||
		TeamMembershipService:   store.TeamMembershipService,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,6 +108,9 @@ func (m *Migrator) Migrate() error {
 | 
			
		|||
 | 
			
		||||
		// Portainer 2.15
 | 
			
		||||
		newMigration(60, m.migrateDBVersionToDB60),
 | 
			
		||||
 | 
			
		||||
		// Portainer 2.16
 | 
			
		||||
		newMigration(70, m.migrateDBVersionToDB70),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var lastDbVersion int
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
package migrator
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (m *Migrator) migrateDBVersionToDB70() error {
 | 
			
		||||
	// foreach endpoint
 | 
			
		||||
	endpoints, err := m.endpointService.Endpoints()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, endpoint := range endpoints {
 | 
			
		||||
		// copy snapshots to new object
 | 
			
		||||
		migrateLog.Info("- moving snapshots from endpoint to new object")
 | 
			
		||||
		snapshot := portainer.Snapshot{EndpointID: endpoint.ID}
 | 
			
		||||
 | 
			
		||||
		if len(endpoint.Snapshots) > 0 {
 | 
			
		||||
			snapshot.Docker = &endpoint.Snapshots[len(endpoint.Snapshots)-1]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(endpoint.Kubernetes.Snapshots) > 0 {
 | 
			
		||||
			snapshot.Kubernetes = &endpoint.Kubernetes.Snapshots[len(endpoint.Kubernetes.Snapshots)-1]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// save new object
 | 
			
		||||
		err = m.snapshotService.Create(&snapshot)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// set to nil old fields
 | 
			
		||||
		migrateLog.Info("- deleting snapshot from endpoint")
 | 
			
		||||
		endpoint.Snapshots = []portainer.DockerSnapshot{}
 | 
			
		||||
		endpoint.Kubernetes.Snapshots = []portainer.KubernetesSnapshot{}
 | 
			
		||||
 | 
			
		||||
		// update endpoint
 | 
			
		||||
		err = m.endpointService.UpdateEndpoint(endpoint.ID, &endpoint)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ import (
 | 
			
		|||
	"github.com/portainer/portainer/api/dataservices/role"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/schedule"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/settings"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/snapshot"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/stack"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/tag"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/teammembership"
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +36,7 @@ type (
 | 
			
		|||
		roleService             *role.Service
 | 
			
		||||
		scheduleService         *schedule.Service
 | 
			
		||||
		settingsService         *settings.Service
 | 
			
		||||
		snapshotService         *snapshot.Service
 | 
			
		||||
		stackService            *stack.Service
 | 
			
		||||
		tagService              *tag.Service
 | 
			
		||||
		teamMembershipService   *teammembership.Service
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +60,7 @@ type (
 | 
			
		|||
		RoleService             *role.Service
 | 
			
		||||
		ScheduleService         *schedule.Service
 | 
			
		||||
		SettingsService         *settings.Service
 | 
			
		||||
		SnapshotService         *snapshot.Service
 | 
			
		||||
		StackService            *stack.Service
 | 
			
		||||
		TagService              *tag.Service
 | 
			
		||||
		TeamMembershipService   *teammembership.Service
 | 
			
		||||
| 
						 | 
				
			
			@ -83,6 +86,7 @@ func NewMigrator(parameters *MigratorParameters) *Migrator {
 | 
			
		|||
		roleService:             parameters.RoleService,
 | 
			
		||||
		scheduleService:         parameters.ScheduleService,
 | 
			
		||||
		settingsService:         parameters.SettingsService,
 | 
			
		||||
		snapshotService:         parameters.SnapshotService,
 | 
			
		||||
		tagService:              parameters.TagService,
 | 
			
		||||
		teamMembershipService:   parameters.TeamMembershipService,
 | 
			
		||||
		stackService:            parameters.StackService,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ import (
 | 
			
		|||
	"github.com/portainer/portainer/api/dataservices/role"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/schedule"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/settings"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/snapshot"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/ssl"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/stack"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices/tag"
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +64,7 @@ type Store struct {
 | 
			
		|||
	APIKeyRepositoryService   *apikeyrepository.Service
 | 
			
		||||
	ScheduleService           *schedule.Service
 | 
			
		||||
	SettingsService           *settings.Service
 | 
			
		||||
	SnapshotService           *snapshot.Service
 | 
			
		||||
	SSLSettingsService        *ssl.Service
 | 
			
		||||
	StackService              *stack.Service
 | 
			
		||||
	TagService                *tag.Service
 | 
			
		||||
| 
						 | 
				
			
			@ -171,6 +173,12 @@ func (store *Store) initServices() error {
 | 
			
		|||
	}
 | 
			
		||||
	store.SettingsService = settingsService
 | 
			
		||||
 | 
			
		||||
	snapshotService, err := snapshot.NewService(store.connection)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	store.SnapshotService = snapshotService
 | 
			
		||||
 | 
			
		||||
	sslSettingsService, err := ssl.NewService(store.connection)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			@ -315,6 +323,10 @@ func (store *Store) Settings() dataservices.SettingsService {
 | 
			
		|||
	return store.SettingsService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (store *Store) Snapshot() dataservices.SnapshotService {
 | 
			
		||||
	return store.SnapshotService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SSLSettings gives access to the SSL Settings data management layer
 | 
			
		||||
func (store *Store) SSLSettings() dataservices.SSLSettingsService {
 | 
			
		||||
	return store.SSLSettingsService
 | 
			
		||||
| 
						 | 
				
			
			@ -375,6 +387,7 @@ type storeExport struct {
 | 
			
		|||
	Role               []portainer.Role               `json:"roles,omitempty"`
 | 
			
		||||
	Schedules          []portainer.Schedule           `json:"schedules,omitempty"`
 | 
			
		||||
	Settings           portainer.Settings             `json:"settings,omitempty"`
 | 
			
		||||
	Snapshot           []portainer.Snapshot           `json:"snapshots,omitempty"`
 | 
			
		||||
	SSLSettings        portainer.SSLSettings          `json:"ssl,omitempty"`
 | 
			
		||||
	Stack              []portainer.Stack              `json:"stacks,omitempty"`
 | 
			
		||||
	Tag                []portainer.Tag                `json:"tags,omitempty"`
 | 
			
		||||
| 
						 | 
				
			
			@ -503,6 +516,14 @@ func (store *Store) Export(filename string) (err error) {
 | 
			
		|||
		backup.Settings = *settings
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if snapshot, err := store.Snapshot().Snapshots(); err != nil {
 | 
			
		||||
		if !store.IsErrObjectNotFound(err) {
 | 
			
		||||
			logrus.WithError(err).Errorf("Exporting Snapshots")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		backup.Snapshot = snapshot
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if settings, err := store.SSLSettings().Settings(); err != nil {
 | 
			
		||||
		if !store.IsErrObjectNotFound(err) {
 | 
			
		||||
			log.Error().Err(err).Msg("exporting SSL Settings")
 | 
			
		||||
| 
						 | 
				
			
			@ -662,6 +683,10 @@ func (store *Store) Import(filename string) (err error) {
 | 
			
		|||
	store.Settings().UpdateSettings(&backup.Settings)
 | 
			
		||||
	store.SSLSettings().UpdateSettings(&backup.SSLSettings)
 | 
			
		||||
 | 
			
		||||
	for _, v := range backup.Snapshot {
 | 
			
		||||
		store.Snapshot().UpdateSnapshot(&v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, v := range backup.Stack {
 | 
			
		||||
		store.Stack().UpdateStack(v.ID, &v)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,7 +60,7 @@
 | 
			
		|||
          "UseLoadBalancer": false,
 | 
			
		||||
          "UseServerMetrics": false
 | 
			
		||||
        },
 | 
			
		||||
        "Snapshots": null
 | 
			
		||||
        "Snapshots": []
 | 
			
		||||
      },
 | 
			
		||||
      "LastCheckInDate": 0,
 | 
			
		||||
      "Name": "local",
 | 
			
		||||
| 
						 | 
				
			
			@ -77,127 +77,7 @@
 | 
			
		|||
        "allowVolumeBrowserForRegularUsers": false,
 | 
			
		||||
        "enableHostManagementFeatures": false
 | 
			
		||||
      },
 | 
			
		||||
      "Snapshots": [
 | 
			
		||||
        {
 | 
			
		||||
          "DockerSnapshotRaw": {
 | 
			
		||||
            "Containers": null,
 | 
			
		||||
            "Images": null,
 | 
			
		||||
            "Info": {
 | 
			
		||||
              "Architecture": "",
 | 
			
		||||
              "BridgeNfIp6tables": false,
 | 
			
		||||
              "BridgeNfIptables": false,
 | 
			
		||||
              "CPUSet": false,
 | 
			
		||||
              "CPUShares": false,
 | 
			
		||||
              "CgroupDriver": "",
 | 
			
		||||
              "ContainerdCommit": {
 | 
			
		||||
                "Expected": "",
 | 
			
		||||
                "ID": ""
 | 
			
		||||
              },
 | 
			
		||||
              "Containers": 0,
 | 
			
		||||
              "ContainersPaused": 0,
 | 
			
		||||
              "ContainersRunning": 0,
 | 
			
		||||
              "ContainersStopped": 0,
 | 
			
		||||
              "CpuCfsPeriod": false,
 | 
			
		||||
              "CpuCfsQuota": false,
 | 
			
		||||
              "Debug": false,
 | 
			
		||||
              "DefaultRuntime": "",
 | 
			
		||||
              "DockerRootDir": "",
 | 
			
		||||
              "Driver": "",
 | 
			
		||||
              "DriverStatus": null,
 | 
			
		||||
              "ExperimentalBuild": false,
 | 
			
		||||
              "GenericResources": null,
 | 
			
		||||
              "HttpProxy": "",
 | 
			
		||||
              "HttpsProxy": "",
 | 
			
		||||
              "ID": "",
 | 
			
		||||
              "IPv4Forwarding": false,
 | 
			
		||||
              "Images": 0,
 | 
			
		||||
              "IndexServerAddress": "",
 | 
			
		||||
              "InitBinary": "",
 | 
			
		||||
              "InitCommit": {
 | 
			
		||||
                "Expected": "",
 | 
			
		||||
                "ID": ""
 | 
			
		||||
              },
 | 
			
		||||
              "Isolation": "",
 | 
			
		||||
              "KernelMemory": false,
 | 
			
		||||
              "KernelMemoryTCP": false,
 | 
			
		||||
              "KernelVersion": "",
 | 
			
		||||
              "Labels": null,
 | 
			
		||||
              "LiveRestoreEnabled": false,
 | 
			
		||||
              "LoggingDriver": "",
 | 
			
		||||
              "MemTotal": 0,
 | 
			
		||||
              "MemoryLimit": false,
 | 
			
		||||
              "NCPU": 0,
 | 
			
		||||
              "NEventsListener": 0,
 | 
			
		||||
              "NFd": 0,
 | 
			
		||||
              "NGoroutines": 0,
 | 
			
		||||
              "Name": "",
 | 
			
		||||
              "NoProxy": "",
 | 
			
		||||
              "OSType": "",
 | 
			
		||||
              "OSVersion": "",
 | 
			
		||||
              "OomKillDisable": false,
 | 
			
		||||
              "OperatingSystem": "",
 | 
			
		||||
              "PidsLimit": false,
 | 
			
		||||
              "Plugins": {
 | 
			
		||||
                "Authorization": null,
 | 
			
		||||
                "Log": null,
 | 
			
		||||
                "Network": null,
 | 
			
		||||
                "Volume": null
 | 
			
		||||
              },
 | 
			
		||||
              "RegistryConfig": null,
 | 
			
		||||
              "RuncCommit": {
 | 
			
		||||
                "Expected": "",
 | 
			
		||||
                "ID": ""
 | 
			
		||||
              },
 | 
			
		||||
              "Runtimes": null,
 | 
			
		||||
              "SecurityOptions": null,
 | 
			
		||||
              "ServerVersion": "",
 | 
			
		||||
              "SwapLimit": false,
 | 
			
		||||
              "Swarm": {
 | 
			
		||||
                "ControlAvailable": false,
 | 
			
		||||
                "Error": "",
 | 
			
		||||
                "LocalNodeState": "",
 | 
			
		||||
                "NodeAddr": "",
 | 
			
		||||
                "NodeID": "",
 | 
			
		||||
                "RemoteManagers": null
 | 
			
		||||
              },
 | 
			
		||||
              "SystemTime": "",
 | 
			
		||||
              "Warnings": null
 | 
			
		||||
            },
 | 
			
		||||
            "Networks": null,
 | 
			
		||||
            "Version": {
 | 
			
		||||
              "ApiVersion": "",
 | 
			
		||||
              "Arch": "",
 | 
			
		||||
              "GitCommit": "",
 | 
			
		||||
              "GoVersion": "",
 | 
			
		||||
              "Os": "",
 | 
			
		||||
              "Platform": {
 | 
			
		||||
                "Name": ""
 | 
			
		||||
              },
 | 
			
		||||
              "Version": ""
 | 
			
		||||
            },
 | 
			
		||||
            "Volumes": {
 | 
			
		||||
              "Volumes": null,
 | 
			
		||||
              "Warnings": null
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          "DockerVersion": "20.10.13",
 | 
			
		||||
          "GpuUseAll": false,
 | 
			
		||||
          "GpuUseList": null,
 | 
			
		||||
          "HealthyContainerCount": 0,
 | 
			
		||||
          "ImageCount": 9,
 | 
			
		||||
          "NodeCount": 0,
 | 
			
		||||
          "RunningContainerCount": 5,
 | 
			
		||||
          "ServiceCount": 0,
 | 
			
		||||
          "StackCount": 2,
 | 
			
		||||
          "StoppedContainerCount": 0,
 | 
			
		||||
          "Swarm": false,
 | 
			
		||||
          "Time": 1648610112,
 | 
			
		||||
          "TotalCPU": 8,
 | 
			
		||||
          "TotalMemory": 25098706944,
 | 
			
		||||
          "UnhealthyContainerCount": 0,
 | 
			
		||||
          "VolumeCount": 10
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "Snapshots": [],
 | 
			
		||||
      "Status": 1,
 | 
			
		||||
      "TLSConfig": {
 | 
			
		||||
        "TLS": false,
 | 
			
		||||
| 
						 | 
				
			
			@ -777,6 +657,131 @@
 | 
			
		|||
      "mpsUser": ""
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "snapshots": [
 | 
			
		||||
    {
 | 
			
		||||
      "Docker": {
 | 
			
		||||
        "DockerSnapshotRaw": {
 | 
			
		||||
          "Containers": null,
 | 
			
		||||
          "Images": null,
 | 
			
		||||
          "Info": {
 | 
			
		||||
            "Architecture": "",
 | 
			
		||||
            "BridgeNfIp6tables": false,
 | 
			
		||||
            "BridgeNfIptables": false,
 | 
			
		||||
            "CPUSet": false,
 | 
			
		||||
            "CPUShares": false,
 | 
			
		||||
            "CgroupDriver": "",
 | 
			
		||||
            "ContainerdCommit": {
 | 
			
		||||
              "Expected": "",
 | 
			
		||||
              "ID": ""
 | 
			
		||||
            },
 | 
			
		||||
            "Containers": 0,
 | 
			
		||||
            "ContainersPaused": 0,
 | 
			
		||||
            "ContainersRunning": 0,
 | 
			
		||||
            "ContainersStopped": 0,
 | 
			
		||||
            "CpuCfsPeriod": false,
 | 
			
		||||
            "CpuCfsQuota": false,
 | 
			
		||||
            "Debug": false,
 | 
			
		||||
            "DefaultRuntime": "",
 | 
			
		||||
            "DockerRootDir": "",
 | 
			
		||||
            "Driver": "",
 | 
			
		||||
            "DriverStatus": null,
 | 
			
		||||
            "ExperimentalBuild": false,
 | 
			
		||||
            "GenericResources": null,
 | 
			
		||||
            "HttpProxy": "",
 | 
			
		||||
            "HttpsProxy": "",
 | 
			
		||||
            "ID": "",
 | 
			
		||||
            "IPv4Forwarding": false,
 | 
			
		||||
            "Images": 0,
 | 
			
		||||
            "IndexServerAddress": "",
 | 
			
		||||
            "InitBinary": "",
 | 
			
		||||
            "InitCommit": {
 | 
			
		||||
              "Expected": "",
 | 
			
		||||
              "ID": ""
 | 
			
		||||
            },
 | 
			
		||||
            "Isolation": "",
 | 
			
		||||
            "KernelMemory": false,
 | 
			
		||||
            "KernelMemoryTCP": false,
 | 
			
		||||
            "KernelVersion": "",
 | 
			
		||||
            "Labels": null,
 | 
			
		||||
            "LiveRestoreEnabled": false,
 | 
			
		||||
            "LoggingDriver": "",
 | 
			
		||||
            "MemTotal": 0,
 | 
			
		||||
            "MemoryLimit": false,
 | 
			
		||||
            "NCPU": 0,
 | 
			
		||||
            "NEventsListener": 0,
 | 
			
		||||
            "NFd": 0,
 | 
			
		||||
            "NGoroutines": 0,
 | 
			
		||||
            "Name": "",
 | 
			
		||||
            "NoProxy": "",
 | 
			
		||||
            "OSType": "",
 | 
			
		||||
            "OSVersion": "",
 | 
			
		||||
            "OomKillDisable": false,
 | 
			
		||||
            "OperatingSystem": "",
 | 
			
		||||
            "PidsLimit": false,
 | 
			
		||||
            "Plugins": {
 | 
			
		||||
              "Authorization": null,
 | 
			
		||||
              "Log": null,
 | 
			
		||||
              "Network": null,
 | 
			
		||||
              "Volume": null
 | 
			
		||||
            },
 | 
			
		||||
            "RegistryConfig": null,
 | 
			
		||||
            "RuncCommit": {
 | 
			
		||||
              "Expected": "",
 | 
			
		||||
              "ID": ""
 | 
			
		||||
            },
 | 
			
		||||
            "Runtimes": null,
 | 
			
		||||
            "SecurityOptions": null,
 | 
			
		||||
            "ServerVersion": "",
 | 
			
		||||
            "SwapLimit": false,
 | 
			
		||||
            "Swarm": {
 | 
			
		||||
              "ControlAvailable": false,
 | 
			
		||||
              "Error": "",
 | 
			
		||||
              "LocalNodeState": "",
 | 
			
		||||
              "NodeAddr": "",
 | 
			
		||||
              "NodeID": "",
 | 
			
		||||
              "RemoteManagers": null
 | 
			
		||||
            },
 | 
			
		||||
            "SystemTime": "",
 | 
			
		||||
            "Warnings": null
 | 
			
		||||
          },
 | 
			
		||||
          "Networks": null,
 | 
			
		||||
          "Version": {
 | 
			
		||||
            "ApiVersion": "",
 | 
			
		||||
            "Arch": "",
 | 
			
		||||
            "GitCommit": "",
 | 
			
		||||
            "GoVersion": "",
 | 
			
		||||
            "Os": "",
 | 
			
		||||
            "Platform": {
 | 
			
		||||
              "Name": ""
 | 
			
		||||
            },
 | 
			
		||||
            "Version": ""
 | 
			
		||||
          },
 | 
			
		||||
          "Volumes": {
 | 
			
		||||
            "Volumes": null,
 | 
			
		||||
            "Warnings": null
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        "DockerVersion": "20.10.13",
 | 
			
		||||
        "GpuUseAll": false,
 | 
			
		||||
        "GpuUseList": null,
 | 
			
		||||
        "HealthyContainerCount": 0,
 | 
			
		||||
        "ImageCount": 9,
 | 
			
		||||
        "NodeCount": 0,
 | 
			
		||||
        "RunningContainerCount": 5,
 | 
			
		||||
        "ServiceCount": 0,
 | 
			
		||||
        "StackCount": 2,
 | 
			
		||||
        "StoppedContainerCount": 0,
 | 
			
		||||
        "Swarm": false,
 | 
			
		||||
        "Time": 1648610112,
 | 
			
		||||
        "TotalCPU": 8,
 | 
			
		||||
        "TotalMemory": 25098706944,
 | 
			
		||||
        "UnhealthyContainerCount": 0,
 | 
			
		||||
        "VolumeCount": 10
 | 
			
		||||
      },
 | 
			
		||||
      "EndpointId": 1,
 | 
			
		||||
      "Kubernetes": null
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "ssl": {
 | 
			
		||||
    "certPath": "",
 | 
			
		||||
    "httpEnabled": true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,15 @@ func initDemoLocalEndpoint(store dataservices.DataStore) (portainer.EndpointID,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	err := store.Endpoint().Create(localEndpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return id, errors.WithMessage(err, "failed creating local endpoint")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = store.Snapshot().Create(&portainer.Snapshot{EndpointID: id})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return id, errors.WithMessage(err, "failed creating snapshot")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return id, errors.WithMessage(err, "failed creating local endpoint")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,5 +44,18 @@ func (handler *Handler) endpointInspect(w http.ResponseWriter, r *http.Request)
 | 
			
		|||
	hideFields(endpoint)
 | 
			
		||||
	endpoint.ComposeSyntaxMaxVersion = handler.ComposeStackManager.ComposeSyntaxMaxVersion()
 | 
			
		||||
 | 
			
		||||
	if !excludeSnapshot(r) {
 | 
			
		||||
		err = handler.SnapshotService.FillSnapshotData(endpoint)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return httperror.InternalServerError("Unable to add snapshot data", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return response.JSON(w, endpoint)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func excludeSnapshot(r *http.Request) bool {
 | 
			
		||||
	excludeSnapshot, _ := request.RetrieveBooleanQueryParameter(r, "excludeSnapshot", true)
 | 
			
		||||
 | 
			
		||||
	return excludeSnapshot
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,6 +103,12 @@ func (handler *Handler) endpointList(w http.ResponseWriter, r *http.Request) *ht
 | 
			
		|||
			paginatedEndpoints[idx].EdgeCheckinInterval = settings.EdgeAgentCheckinInterval
 | 
			
		||||
		}
 | 
			
		||||
		paginatedEndpoints[idx].QueryDate = time.Now().Unix()
 | 
			
		||||
		if !query.excludeSnapshots {
 | 
			
		||||
			err = handler.SnapshotService.FillSnapshotData(&paginatedEndpoints[idx])
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return httperror.InternalServerError("Unable to add snapshot data", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w.Header().Set("X-Total-Count", strconv.Itoa(filteredEndpointCount))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ import (
 | 
			
		|||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/datastore"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/snapshot"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
	helper "github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
| 
						 | 
				
			
			@ -203,6 +204,8 @@ func setup(t *testing.T, endpoints []portainer.Endpoint) (handler *Handler, tear
 | 
			
		|||
	handler.DataStore = store
 | 
			
		||||
	handler.ComposeStackManager = testhelpers.NewComposeStackManager()
 | 
			
		||||
 | 
			
		||||
	handler.SnapshotService, _ = snapshot.NewService("1s", store, nil, nil, nil)
 | 
			
		||||
 | 
			
		||||
	return handler, teardown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,8 +53,6 @@ func (handler *Handler) endpointSnapshot(w http.ResponseWriter, r *http.Request)
 | 
			
		|||
		latestEndpointReference.Status = portainer.EndpointStatusDown
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	latestEndpointReference.Snapshots = endpoint.Snapshots
 | 
			
		||||
	latestEndpointReference.Kubernetes.Snapshots = endpoint.Kubernetes.Snapshots
 | 
			
		||||
	latestEndpointReference.Agent.Version = endpoint.Agent.Version
 | 
			
		||||
 | 
			
		||||
	err = handler.DataStore.Endpoint().UpdateEndpoint(latestEndpointReference.ID, latestEndpointReference)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,8 +56,6 @@ func (handler *Handler) endpointSnapshots(w http.ResponseWriter, r *http.Request
 | 
			
		|||
			endpoint.Status = portainer.EndpointStatusDown
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		latestEndpointReference.Snapshots = endpoint.Snapshots
 | 
			
		||||
		latestEndpointReference.Kubernetes.Snapshots = endpoint.Kubernetes.Snapshots
 | 
			
		||||
		latestEndpointReference.Agent.Version = endpoint.Agent.Version
 | 
			
		||||
 | 
			
		||||
		err = handler.DataStore.Endpoint().UpdateEndpoint(latestEndpointReference.ID, latestEndpointReference)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -329,5 +329,10 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) *
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = handler.SnapshotService.FillSnapshotData(endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return &httperror.HandlerError{http.StatusInternalServerError, "Unable to add snapshot data", err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return response.JSON(w, endpoint)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ type EnvironmentsQuery struct {
 | 
			
		|||
	status              []portainer.EndpointStatus
 | 
			
		||||
	edgeDevice          *bool
 | 
			
		||||
	edgeDeviceUntrusted bool
 | 
			
		||||
	excludeSnapshots    bool
 | 
			
		||||
	name                string
 | 
			
		||||
	agentVersions       []string
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +75,8 @@ func parseQuery(r *http.Request) (EnvironmentsQuery, error) {
 | 
			
		|||
 | 
			
		||||
	edgeDeviceUntrusted, _ := request.RetrieveBooleanQueryParameter(r, "edgeDeviceUntrusted", true)
 | 
			
		||||
 | 
			
		||||
	excludeSnapshots, _ := request.RetrieveBooleanQueryParameter(r, "excludeSnapshots", true)
 | 
			
		||||
 | 
			
		||||
	return EnvironmentsQuery{
 | 
			
		||||
		search:              search,
 | 
			
		||||
		types:               endpointTypes,
 | 
			
		||||
| 
						 | 
				
			
			@ -84,6 +87,7 @@ func parseQuery(r *http.Request) (EnvironmentsQuery, error) {
 | 
			
		|||
		status:              status,
 | 
			
		||||
		edgeDevice:          edgeDevice,
 | 
			
		||||
		edgeDeviceUntrusted: edgeDeviceUntrusted,
 | 
			
		||||
		excludeSnapshots:    excludeSnapshots,
 | 
			
		||||
		name:                name,
 | 
			
		||||
		agentVersions:       agentVersions,
 | 
			
		||||
	}, nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,15 @@ func (factory *ProxyFactory) newDockerHTTPProxy(endpoint *portainer.Endpoint) (h
 | 
			
		|||
		endpointURL.Scheme = "https"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	snapshot, err := factory.dataStore.Snapshot().Snapshot(endpoint.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if snapshot.Docker != nil {
 | 
			
		||||
		endpoint.Snapshots = []portainer.DockerSnapshot{*snapshot.Docker}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	transportParameters := &docker.TransportParameters{
 | 
			
		||||
		Endpoint:             endpoint,
 | 
			
		||||
		DataStore:            factory.dataStore,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,27 +119,59 @@ func (service *Service) SnapshotEndpoint(endpoint *portainer.Endpoint) error {
 | 
			
		|||
	return service.snapshotDockerEndpoint(endpoint)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) snapshotKubernetesEndpoint(endpoint *portainer.Endpoint) error {
 | 
			
		||||
	snapshot, err := service.kubernetesSnapshotter.CreateSnapshot(endpoint)
 | 
			
		||||
func (service *Service) Create(snapshot portainer.Snapshot) error {
 | 
			
		||||
	return service.dataStore.Snapshot().Create(&snapshot)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) FillSnapshotData(endpoint *portainer.Endpoint) error {
 | 
			
		||||
	snapshot, err := service.dataStore.Snapshot().Snapshot(endpoint.ID)
 | 
			
		||||
	if service.dataStore.IsErrObjectNotFound(err) {
 | 
			
		||||
		endpoint.Snapshots = []portainer.DockerSnapshot{}
 | 
			
		||||
		endpoint.Kubernetes.Snapshots = []portainer.KubernetesSnapshot{}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if snapshot != nil {
 | 
			
		||||
		endpoint.Kubernetes.Snapshots = []portainer.KubernetesSnapshot{*snapshot}
 | 
			
		||||
	if snapshot.Docker != nil {
 | 
			
		||||
		endpoint.Snapshots = []portainer.DockerSnapshot{*snapshot.Docker}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if snapshot.Kubernetes != nil {
 | 
			
		||||
		endpoint.Kubernetes.Snapshots = []portainer.KubernetesSnapshot{*snapshot.Kubernetes}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) snapshotKubernetesEndpoint(endpoint *portainer.Endpoint) error {
 | 
			
		||||
	kubernetesSnapshot, err := service.kubernetesSnapshotter.CreateSnapshot(endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if kubernetesSnapshot != nil {
 | 
			
		||||
		snapshot := &portainer.Snapshot{EndpointID: endpoint.ID, Kubernetes: kubernetesSnapshot}
 | 
			
		||||
 | 
			
		||||
		return service.dataStore.Snapshot().Create(snapshot)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (service *Service) snapshotDockerEndpoint(endpoint *portainer.Endpoint) error {
 | 
			
		||||
	snapshot, err := service.dockerSnapshotter.CreateSnapshot(endpoint)
 | 
			
		||||
	dockerSnapshot, err := service.dockerSnapshotter.CreateSnapshot(endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if snapshot != nil {
 | 
			
		||||
		endpoint.Snapshots = []portainer.DockerSnapshot{*snapshot}
 | 
			
		||||
	if dockerSnapshot != nil {
 | 
			
		||||
		snapshot := &portainer.Snapshot{EndpointID: endpoint.ID, Docker: dockerSnapshot}
 | 
			
		||||
 | 
			
		||||
		return service.dataStore.Snapshot().Create(snapshot)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
| 
						 | 
				
			
			@ -203,8 +235,6 @@ func (service *Service) snapshotEndpoints() error {
 | 
			
		|||
			latestEndpointReference.Status = portainer.EndpointStatusDown
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		latestEndpointReference.Snapshots = endpoint.Snapshots
 | 
			
		||||
		latestEndpointReference.Kubernetes.Snapshots = endpoint.Kubernetes.Snapshots
 | 
			
		||||
		latestEndpointReference.Agent.Version = endpoint.Agent.Version
 | 
			
		||||
 | 
			
		||||
		err = service.dataStore.Endpoint().UpdateEndpoint(latestEndpointReference.ID, latestEndpointReference)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@ type testDatastore struct {
 | 
			
		|||
	role                    dataservices.RoleService
 | 
			
		||||
	sslSettings             dataservices.SSLSettingsService
 | 
			
		||||
	settings                dataservices.SettingsService
 | 
			
		||||
	snapshot                dataservices.SnapshotService
 | 
			
		||||
	stack                   dataservices.StackService
 | 
			
		||||
	tag                     dataservices.TagService
 | 
			
		||||
	teamMembership          dataservices.TeamMembershipService
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +70,7 @@ func (d *testDatastore) APIKeyRepository() dataservices.APIKeyRepository {
 | 
			
		|||
	return d.apiKeyRepositoryService
 | 
			
		||||
}
 | 
			
		||||
func (d *testDatastore) Settings() dataservices.SettingsService             { return d.settings }
 | 
			
		||||
func (d *testDatastore) Snapshot() dataservices.SnapshotService             { return d.snapshot }
 | 
			
		||||
func (d *testDatastore) SSLSettings() dataservices.SSLSettingsService       { return d.sslSettings }
 | 
			
		||||
func (d *testDatastore) Stack() dataservices.StackService                   { return d.stack }
 | 
			
		||||
func (d *testDatastore) Tag() dataservices.TagService                       { return d.tag }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1243,6 +1243,12 @@ type (
 | 
			
		|||
	// WebhookType represents the type of resource a webhook is related to
 | 
			
		||||
	WebhookType int
 | 
			
		||||
 | 
			
		||||
	Snapshot struct {
 | 
			
		||||
		EndpointID EndpointID          `json:"EndpointId"`
 | 
			
		||||
		Docker     *DockerSnapshot     `json:"Docker"`
 | 
			
		||||
		Kubernetes *KubernetesSnapshot `json:"Kubernetes"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// CLIService represents a service for managing CLI
 | 
			
		||||
	CLIService interface {
 | 
			
		||||
		ParseFlags(version string) (*CLIFlags, error)
 | 
			
		||||
| 
						 | 
				
			
			@ -1420,6 +1426,7 @@ type (
 | 
			
		|||
		Start()
 | 
			
		||||
		SetSnapshotInterval(snapshotInterval string) error
 | 
			
		||||
		SnapshotEndpoint(endpoint *Endpoint) error
 | 
			
		||||
		FillSnapshotData(endpoint *Endpoint) error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// SwarmStackManager represents a service to manage Swarm stacks
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,6 +92,7 @@ function Loader({ children, storageKey }: LoaderProps) {
 | 
			
		|||
      edgeDevice: true,
 | 
			
		||||
      search: debouncedSearchValue,
 | 
			
		||||
      types: EdgeTypes,
 | 
			
		||||
      excludeSnapshots: true,
 | 
			
		||||
      ...pagination,
 | 
			
		||||
    },
 | 
			
		||||
    settings.autoRefreshRate * 1000
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@ export function WaitingRoomView() {
 | 
			
		|||
  const { environments, isLoading, totalCount } = useEnvironmentList({
 | 
			
		||||
    edgeDevice: true,
 | 
			
		||||
    edgeDeviceUntrusted: true,
 | 
			
		||||
    excludeSnapshots: true,
 | 
			
		||||
    types: EdgeTypes,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ export interface EnvironmentsQueryParams {
 | 
			
		|||
  status?: EnvironmentStatus[];
 | 
			
		||||
  edgeDevice?: boolean;
 | 
			
		||||
  edgeDeviceUntrusted?: boolean;
 | 
			
		||||
  excludeSnapshots?: boolean;
 | 
			
		||||
  provisioned?: boolean;
 | 
			
		||||
  name?: string;
 | 
			
		||||
  agentVersions?: string[];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ function EndpointsController($q, $scope, $state, $async, EndpointService, GroupS
 | 
			
		|||
  function getPaginatedEndpoints(start, limit, search) {
 | 
			
		||||
    const deferred = $q.defer();
 | 
			
		||||
    $q.all({
 | 
			
		||||
      endpoints: getEnvironments({ start, limit, query: { search } }),
 | 
			
		||||
      endpoints: getEnvironments({ start, limit, query: { search, excludeSnapshots: true } }),
 | 
			
		||||
      groups: GroupService.groups(),
 | 
			
		||||
    })
 | 
			
		||||
      .then(function success(data) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue