github.com/LINBIT/golinstor@v0.52.0/cache/resource.go (about) 1 package cache 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/LINBIT/golinstor/client" 8 ) 9 10 // ResourceCache caches responses from a client.ResourceProvider. 11 type ResourceCache struct { 12 // Timeout for the cached responses. 13 Timeout time.Duration 14 15 resourceCache cache 16 snapshotCache cache 17 } 18 19 func (r *ResourceCache) apply(c *client.Client) { 20 c.Resources = &resourceCacheProvider{ 21 cl: c.Resources, 22 cache: r, 23 } 24 } 25 26 type resourceCacheProvider struct { 27 cl client.ResourceProvider 28 cache *ResourceCache 29 } 30 31 var _ client.ResourceProvider = &resourceCacheProvider{} 32 33 func (r *resourceCacheProvider) GetResourceView(ctx context.Context, opts ...*client.ListOpts) ([]client.ResourceWithVolumes, error) { 34 result, err := r.cache.resourceCache.Get(r.cache.Timeout, func() (any, error) { 35 return r.cl.GetResourceView(ctx, cacheOpt) 36 }) 37 if err != nil { 38 return nil, err 39 } 40 41 return filterNodeAndPoolOpts(result.([]client.ResourceWithVolumes), func(c *client.ResourceWithVolumes) ([]string, []string) { 42 return []string{c.NodeName}, nil 43 }, opts...), nil 44 } 45 46 func (r *resourceCacheProvider) GetAll(ctx context.Context, resName string, opts ...*client.ListOpts) ([]client.Resource, error) { 47 ress, err := r.GetResourceView(ctx, opts...) 48 if err != nil { 49 return nil, err 50 } 51 52 var result []client.Resource 53 54 for i := range ress { 55 if ress[i].Name == resName { 56 result = append(result, ress[i].Resource) 57 } 58 } 59 60 return result, nil 61 } 62 63 func (r *resourceCacheProvider) Get(ctx context.Context, resName, nodeName string, opts ...*client.ListOpts) (client.Resource, error) { 64 ress, err := r.GetAll(ctx, resName, opts...) 65 if err != nil { 66 return client.Resource{}, err 67 } 68 69 for i := range ress { 70 if ress[i].NodeName == nodeName { 71 return ress[i], nil 72 } 73 } 74 return client.Resource{}, client.NotFoundError 75 } 76 77 func (r *resourceCacheProvider) GetVolumes(ctx context.Context, resName, nodeName string, opts ...*client.ListOpts) ([]client.Volume, error) { 78 ress, err := r.GetResourceView(ctx, opts...) 79 if err != nil { 80 return nil, err 81 } 82 83 var result []client.Volume 84 for i := range ress { 85 if ress[i].NodeName != nodeName || ress[i].Name != resName { 86 continue 87 } 88 89 for j := range ress[i].Volumes { 90 result = append(result, ress[i].Volumes[j]) 91 } 92 } 93 94 return result, nil 95 } 96 97 func (r *resourceCacheProvider) GetVolume(ctx context.Context, resName, nodeName string, volNr int, opts ...*client.ListOpts) (client.Volume, error) { 98 volumes, err := r.GetVolumes(ctx, resName, nodeName, opts...) 99 if err != nil { 100 return client.Volume{}, err 101 } 102 103 for i := range volumes { 104 if int(volumes[i].VolumeNumber) == volNr { 105 return volumes[i], nil 106 } 107 } 108 109 return client.Volume{}, client.NotFoundError 110 } 111 112 func (r *resourceCacheProvider) Create(ctx context.Context, res client.ResourceCreate) error { 113 r.cache.resourceCache.Invalidate() 114 return r.cl.Create(ctx, res) 115 } 116 117 func (r *resourceCacheProvider) Modify(ctx context.Context, resName, nodeName string, props client.GenericPropsModify) error { 118 r.cache.resourceCache.Invalidate() 119 return r.cl.Modify(ctx, resName, nodeName, props) 120 } 121 122 func (r *resourceCacheProvider) Delete(ctx context.Context, resName, nodeName string) error { 123 r.cache.resourceCache.Invalidate() 124 return r.cl.Delete(ctx, resName, nodeName) 125 } 126 127 func (r *resourceCacheProvider) ModifyVolume(ctx context.Context, resName, nodeName string, volNr int, props client.GenericPropsModify) error { 128 r.cache.resourceCache.Invalidate() 129 return r.cl.ModifyVolume(ctx, resName, nodeName, volNr, props) 130 } 131 132 func (r *resourceCacheProvider) Diskless(ctx context.Context, resName, nodeName, disklessPoolName string) error { 133 r.cache.resourceCache.Invalidate() 134 return r.cl.Diskless(ctx, resName, nodeName, disklessPoolName) 135 } 136 137 func (r *resourceCacheProvider) Diskful(ctx context.Context, resName, nodeName, storagePoolName string, props *client.ToggleDiskDiskfulProps) error { 138 r.cache.resourceCache.Invalidate() 139 return r.cl.Diskful(ctx, resName, nodeName, storagePoolName, props) 140 } 141 142 func (r *resourceCacheProvider) Migrate(ctx context.Context, resName, fromNodeName, toNodeName, storagePoolName string) error { 143 r.cache.resourceCache.Invalidate() 144 return r.cl.Migrate(ctx, resName, fromNodeName, toNodeName, storagePoolName) 145 } 146 147 func (r *resourceCacheProvider) Autoplace(ctx context.Context, resName string, apr client.AutoPlaceRequest) error { 148 r.cache.resourceCache.Invalidate() 149 return r.cl.Autoplace(ctx, resName, apr) 150 } 151 152 func (r *resourceCacheProvider) Activate(ctx context.Context, resName string, nodeName string) error { 153 r.cache.resourceCache.Invalidate() 154 return r.cl.Activate(ctx, resName, nodeName) 155 } 156 157 func (r *resourceCacheProvider) Deactivate(ctx context.Context, resName string, nodeName string) error { 158 r.cache.resourceCache.Invalidate() 159 return r.cl.Deactivate(ctx, resName, nodeName) 160 } 161 162 func (r *resourceCacheProvider) MakeAvailable(ctx context.Context, resName, nodeName string, makeAvailable client.ResourceMakeAvailable) error { 163 r.cache.resourceCache.Invalidate() 164 return r.cl.MakeAvailable(ctx, resName, nodeName, makeAvailable) 165 } 166 167 func (r *resourceCacheProvider) GetSnapshotView(ctx context.Context, opts ...*client.ListOpts) ([]client.Snapshot, error) { 168 result, err := r.cache.snapshotCache.Get(r.cache.Timeout, func() (any, error) { 169 return r.cl.GetSnapshotView(ctx, cacheOpt) 170 }) 171 if err != nil { 172 return nil, err 173 } 174 175 return filterNodeAndPoolOpts(result.([]client.Snapshot), func(c *client.Snapshot) ([]string, []string) { 176 return c.Nodes, nil 177 }, opts...), nil 178 } 179 180 func (r *resourceCacheProvider) GetSnapshots(ctx context.Context, resName string, opts ...*client.ListOpts) ([]client.Snapshot, error) { 181 snaps, err := r.GetSnapshotView(ctx, opts...) 182 if err != nil { 183 return nil, err 184 } 185 186 var result []client.Snapshot 187 for i := range snaps { 188 if snaps[i].ResourceName == resName { 189 result = append(result, snaps[i]) 190 } 191 } 192 193 return result, nil 194 } 195 196 func (r *resourceCacheProvider) GetSnapshot(ctx context.Context, resName, snapName string, opts ...*client.ListOpts) (client.Snapshot, error) { 197 snaps, err := r.GetSnapshots(ctx, resName, opts...) 198 if err != nil { 199 return client.Snapshot{}, err 200 } 201 202 for i := range snaps { 203 if snaps[i].Name == snapName { 204 return snaps[i], nil 205 } 206 } 207 208 return client.Snapshot{}, client.NotFoundError 209 } 210 211 func (r *resourceCacheProvider) CreateSnapshot(ctx context.Context, snapshot client.Snapshot) error { 212 r.cache.snapshotCache.Invalidate() 213 return r.cl.CreateSnapshot(ctx, snapshot) 214 } 215 216 func (r *resourceCacheProvider) DeleteSnapshot(ctx context.Context, resName, snapName string, nodes ...string) error { 217 r.cache.snapshotCache.Invalidate() 218 return r.cl.DeleteSnapshot(ctx, resName, snapName, nodes...) 219 } 220 221 func (r *resourceCacheProvider) RestoreSnapshot(ctx context.Context, origResName, snapName string, snapRestoreConf client.SnapshotRestore) error { 222 // This will create new resources, not touch snapshots 223 r.cache.resourceCache.Invalidate() 224 return r.cl.RestoreSnapshot(ctx, origResName, snapName, snapRestoreConf) 225 } 226 227 func (r *resourceCacheProvider) RestoreVolumeDefinitionSnapshot(ctx context.Context, origResName, snapName string, snapRestoreConf client.SnapshotRestore) error { 228 // This will create new resources, not touch snapshots 229 r.cache.resourceCache.Invalidate() 230 return r.cl.RestoreVolumeDefinitionSnapshot(ctx, origResName, snapName, snapRestoreConf) 231 } 232 233 func (r *resourceCacheProvider) RollbackSnapshot(ctx context.Context, resName, snapName string) error { 234 return r.cl.RollbackSnapshot(ctx, resName, snapName) 235 } 236 237 func (r *resourceCacheProvider) GetConnections(ctx context.Context, resName, nodeAName, nodeBName string, opts ...*client.ListOpts) ([]client.ResourceConnection, error) { 238 return r.cl.GetConnections(ctx, resName, nodeAName, nodeBName, opts...) 239 } 240 241 func (r *resourceCacheProvider) ModifyConnection(ctx context.Context, resName, nodeAName, nodeBName string, props client.GenericPropsModify) error { 242 return r.cl.ModifyConnection(ctx, resName, nodeAName, nodeBName, props) 243 } 244 245 func (r *resourceCacheProvider) EnableSnapshotShipping(ctx context.Context, resName string, ship client.SnapshotShipping) error { 246 return r.cl.EnableSnapshotShipping(ctx, resName, ship) 247 } 248 249 func (r *resourceCacheProvider) ModifyDRBDProxy(ctx context.Context, resName string, props client.DrbdProxyModify) error { 250 return r.cl.ModifyDRBDProxy(ctx, resName, props) 251 } 252 253 func (r *resourceCacheProvider) EnableDRBDProxy(ctx context.Context, resName, nodeAName, nodeBName string) error { 254 return r.cl.EnableDRBDProxy(ctx, resName, nodeAName, nodeBName) 255 } 256 257 func (r *resourceCacheProvider) DisableDRBDProxy(ctx context.Context, resName, nodeAName, nodeBName string) error { 258 return r.cl.DisableDRBDProxy(ctx, resName, nodeAName, nodeBName) 259 } 260 261 func (r *resourceCacheProvider) QueryMaxVolumeSize(ctx context.Context, filter client.AutoSelectFilter) (client.MaxVolumeSizes, error) { 262 return r.cl.QueryMaxVolumeSize(ctx, filter) 263 } 264 265 func (r *resourceCacheProvider) GetSnapshotShippings(ctx context.Context, opts ...*client.ListOpts) ([]client.SnapshotShippingStatus, error) { 266 return r.cl.GetSnapshotShippings(ctx, opts...) 267 } 268 269 func (r *resourceCacheProvider) GetPropsInfos(ctx context.Context, resName string, opts ...*client.ListOpts) ([]client.PropsInfo, error) { 270 return r.cl.GetPropsInfos(ctx, resName, opts...) 271 } 272 273 func (r *resourceCacheProvider) GetVolumeDefinitionPropsInfos(ctx context.Context, resName string, opts ...*client.ListOpts) ([]client.PropsInfo, error) { 274 return r.cl.GetVolumeDefinitionPropsInfos(ctx, resName, opts...) 275 } 276 277 func (r *resourceCacheProvider) GetVolumePropsInfos(ctx context.Context, resName, nodeName string, opts ...*client.ListOpts) ([]client.PropsInfo, error) { 278 return r.cl.GetVolumePropsInfos(ctx, resName, nodeName, opts...) 279 } 280 281 func (r *resourceCacheProvider) GetConnectionPropsInfos(ctx context.Context, resName string, opts ...*client.ListOpts) ([]client.PropsInfo, error) { 282 return r.cl.GetConnectionPropsInfos(ctx, resName, opts...) 283 }