From 0b2217a916d4a47de2fb4417d289397e15abccbe Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Thu, 26 May 2022 15:34:34 +0300 Subject: [PATCH] refactor(docker): strongly type snapshot [EE-3256] fixes [EE-3256] --- api/datastore/migrator/migrate_dbversion31.go | 34 +++---- api/datastore/test_data/output_35.json | 99 ++++++++++++++++++- api/internal/snapshot/snapshot.go | 19 ++-- api/portainer.go | 15 +-- 4 files changed, 125 insertions(+), 42 deletions(-) diff --git a/api/datastore/migrator/migrate_dbversion31.go b/api/datastore/migrator/migrate_dbversion31.go index 7e4249421..f474d7a06 100644 --- a/api/datastore/migrator/migrate_dbversion31.go +++ b/api/datastore/migrator/migrate_dbversion31.go @@ -4,6 +4,7 @@ import ( "fmt" "log" + "github.com/docker/docker/api/types/volume" "github.com/portainer/portainer/api/dataservices/errors" portainer "github.com/portainer/portainer/api" @@ -206,18 +207,18 @@ func (m *Migrator) updateVolumeResourceControlToDB32() error { endpointDockerID, err := snapshotutils.FetchDockerID(snapshot) if err != nil { - log.Printf("[WARN] [database,migrator,v31] [message: failed fetching environment docker id] [err: %s]", err) + log.Printf("[WARN] [bolt,migrator,v31] [message: failed fetching environment docker id] [err: %s]", err) continue } - if volumesData, done := snapshot.SnapshotRaw.Volumes.(map[string]interface{}); done { - if volumesData["Volumes"] == nil { - log.Println("[DEBUG] [volume migration] [message: no volume data found]") - continue - } - - findResourcesToUpdateForDB32(endpointDockerID, volumesData, toUpdate, volumeResourceControls) + volumesData := snapshot.SnapshotRaw.Volumes + if volumesData.Volumes == nil { + log.Println("[DEBUG] [volume migration] [message: no volume data found]") + continue } + + findResourcesToUpdateToDB32(endpointDockerID, volumesData, toUpdate, volumeResourceControls) + } for _, resourceControl := range volumeResourceControls { @@ -240,18 +241,11 @@ func (m *Migrator) updateVolumeResourceControlToDB32() error { return nil } -func findResourcesToUpdateForDB32(dockerID string, volumesData map[string]interface{}, toUpdate map[portainer.ResourceControlID]string, volumeResourceControls map[string]*portainer.ResourceControl) { - volumes := volumesData["Volumes"].([]interface{}) - for _, volumeMeta := range volumes { - volume := volumeMeta.(map[string]interface{}) - volumeName, nameExist := volume["Name"].(string) - if !nameExist { - continue - } - createTime, createTimeExist := volume["CreatedAt"].(string) - if !createTimeExist { - continue - } +func findResourcesToUpdateToDB32(dockerID string, volumesData volume.VolumeListOKBody, toUpdate map[portainer.ResourceControlID]string, volumeResourceControls map[string]*portainer.ResourceControl) { + volumes := volumesData.Volumes + for _, volume := range volumes { + volumeName := volume.Name + createTime := volume.CreatedAt oldResourceID := fmt.Sprintf("%s%s", volumeName, createTime) resourceControl, ok := volumeResourceControls[oldResourceID] diff --git a/api/datastore/test_data/output_35.json b/api/datastore/test_data/output_35.json index b8ce03ef4..db47663be 100644 --- a/api/datastore/test_data/output_35.json +++ b/api/datastore/test_data/output_35.json @@ -70,10 +70,103 @@ "DockerSnapshotRaw": { "Containers": null, "Images": null, - "Info": 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": null, - "Volumes": null + "Version": { + "ApiVersion": "", + "Arch": "", + "GitCommit": "", + "GoVersion": "", + "Os": "", + "Platform": { + "Name": "" + }, + "Version": "" + }, + "Volumes": { + "Volumes": null, + "Warnings": null + } }, "DockerVersion": "20.10.13", "HealthyContainerCount": 0, diff --git a/api/internal/snapshot/snapshot.go b/api/internal/snapshot/snapshot.go index 3aa943908..e20cf21ef 100644 --- a/api/internal/snapshot/snapshot.go +++ b/api/internal/snapshot/snapshot.go @@ -188,24 +188,17 @@ func (service *Service) snapshotEndpoints() error { // FetchDockerID fetches info.Swarm.Cluster.ID if environment(endpoint) is swarm and info.ID otherwise func FetchDockerID(snapshot portainer.DockerSnapshot) (string, error) { - info, done := snapshot.SnapshotRaw.Info.(map[string]interface{}) - if !done { - return "", errors.New("failed getting snapshot info") - } + info := snapshot.SnapshotRaw.Info if !snapshot.Swarm { - return info["ID"].(string), nil + return info.ID, nil } - if info["Swarm"] == nil { - return "", errors.New("swarm environment is missing swarm info snapshot") - } - - swarmInfo := info["Swarm"].(map[string]interface{}) - if swarmInfo["Cluster"] == nil { + swarmInfo := info.Swarm + if swarmInfo.Cluster == nil { return "", errors.New("swarm environment is missing cluster info snapshot") } - clusterInfo := swarmInfo["Cluster"].(map[string]interface{}) - return clusterInfo["ID"].(string), nil + clusterInfo := swarmInfo.Cluster + return clusterInfo.ID, nil } diff --git a/api/portainer.go b/api/portainer.go index 0b081e3ce..4351dad5e 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -5,6 +5,8 @@ import ( "io" "time" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/volume" gittypes "github.com/portainer/portainer/api/git/types" v1 "k8s.io/api/core/v1" ) @@ -191,13 +193,14 @@ type ( } // DockerSnapshotRaw represents all the information related to a snapshot as returned by the Docker API + DockerSnapshotRaw struct { - Containers interface{} `json:"Containers"` - Volumes interface{} `json:"Volumes"` - Networks interface{} `json:"Networks"` - Images interface{} `json:"Images"` - Info interface{} `json:"Info"` - Version interface{} `json:"Version"` + Containers []types.Container `json:"Containers"` + Volumes volume.VolumeListOKBody `json:"Volumes"` + Networks []types.NetworkResource `json:"Networks"` + Images []types.ImageSummary `json:"Images"` + Info types.Info `json:"Info"` + Version types.Version `json:"Version"` } // EdgeGroup represents an Edge group