2020-08-24 14:07:08 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2021-02-01 12:29:35 +00:00
|
|
|
"bytes"
|
2021-02-01 11:59:35 +00:00
|
|
|
"context"
|
2023-11-30 17:51:23 +00:00
|
|
|
"net"
|
2021-02-01 11:59:35 +00:00
|
|
|
|
2023-03-07 13:38:26 +00:00
|
|
|
containerGRPC "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
|
2024-05-06 16:30:19 +00:00
|
|
|
morphconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/morph"
|
2023-04-12 14:35:10 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
2023-03-07 13:38:26 +00:00
|
|
|
containerCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
2024-05-06 16:30:19 +00:00
|
|
|
frostfsidcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/frostfsid"
|
2023-03-07 13:38:26 +00:00
|
|
|
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
2024-01-29 21:03:18 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
2023-03-07 13:38:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
|
|
|
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
|
|
|
containerTransportGRPC "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network/transport/container/grpc"
|
|
|
|
containerService "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/container"
|
|
|
|
containerMorph "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/container/morph"
|
|
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
2024-07-01 15:42:15 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
2021-02-01 11:21:24 +00:00
|
|
|
"go.uber.org/zap"
|
2023-11-30 17:51:23 +00:00
|
|
|
"google.golang.org/grpc"
|
2020-08-24 14:07:08 +00:00
|
|
|
)
|
|
|
|
|
2023-10-06 10:54:48 +00:00
|
|
|
func initContainerService(_ context.Context, c *cfg) {
|
2021-09-09 14:13:35 +00:00
|
|
|
// container wrapper that tries to invoke notary
|
|
|
|
// requests if chain is configured so
|
2022-01-31 13:34:01 +00:00
|
|
|
wrap, err := cntClient.NewFromMorph(c.cfgMorph.client, c.cfgContainer.scriptHash, 0, cntClient.TryNotary())
|
2020-09-24 07:46:47 +00:00
|
|
|
fatalOnErr(err)
|
|
|
|
|
2022-10-06 20:18:46 +00:00
|
|
|
c.shared.cnrClient = wrap
|
|
|
|
|
2022-01-31 13:34:01 +00:00
|
|
|
cnrSrc := cntClient.AsContainerSource(wrap)
|
2021-05-19 16:32:25 +00:00
|
|
|
|
2023-03-24 07:35:41 +00:00
|
|
|
cnrRdr, cnrWrt := configureEACLAndContainerSources(c, wrap, cnrSrc)
|
|
|
|
|
2024-05-06 16:30:19 +00:00
|
|
|
var frostfsIDSubjectProvider frostfsidcore.SubjectProvider
|
|
|
|
frostfsIDSubjectProvider, err = frostfsid.NewFromMorph(c.cfgMorph.client, c.cfgFrostfsID.scriptHash, 0)
|
2024-01-29 21:03:18 +00:00
|
|
|
fatalOnErr(err)
|
2024-05-06 16:30:19 +00:00
|
|
|
|
|
|
|
cacheSize := morphconfig.FrostfsIDCacheSize(c.appCfg)
|
|
|
|
if cacheSize > 0 {
|
|
|
|
frostfsIDSubjectProvider = newMorphFrostfsIDCache(frostfsIDSubjectProvider, int(cacheSize), c.cfgMorph.cacheTTL)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.shared.frostfsidClient = frostfsIDSubjectProvider
|
2024-01-29 21:03:18 +00:00
|
|
|
|
2024-07-01 15:42:15 +00:00
|
|
|
defaultChainRouter := engine.NewDefaultChainRouterWithLocalOverrides(
|
|
|
|
c.cfgObject.cfgAccessPolicyEngine.accessPolicyEngine.MorphRuleChainStorage(),
|
|
|
|
c.cfgObject.cfgAccessPolicyEngine.accessPolicyEngine.LocalStorage(),
|
|
|
|
)
|
2024-06-18 09:40:03 +00:00
|
|
|
service := containerService.NewSignService(
|
|
|
|
&c.key.PrivateKey,
|
2024-07-01 15:42:15 +00:00
|
|
|
containerService.NewAPEServer(defaultChainRouter, cnrRdr,
|
2024-06-18 09:40:03 +00:00
|
|
|
newCachedIRFetcher(createInnerRingFetcher(c)), c.netMapSource, c.shared.frostfsidClient,
|
|
|
|
containerService.NewExecutionService(containerMorph.NewExecutor(cnrRdr, cnrWrt), c.respSvc),
|
2023-03-24 07:35:41 +00:00
|
|
|
),
|
|
|
|
)
|
2024-06-18 09:40:03 +00:00
|
|
|
service = containerService.NewAuditService(service, c.log, c.audit)
|
|
|
|
server := containerTransportGRPC.New(service)
|
2023-03-24 07:35:41 +00:00
|
|
|
|
2023-11-30 17:51:23 +00:00
|
|
|
c.cfgGRPC.performAndSave(func(_ string, _ net.Listener, s *grpc.Server) {
|
|
|
|
containerGRPC.RegisterContainerServiceServer(s, server)
|
|
|
|
})
|
2023-12-27 15:58:36 +00:00
|
|
|
|
|
|
|
c.cfgObject.cfgLocalStorage.localStorage.SetContainerSource(cnrRdr)
|
2023-03-24 07:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func configureEACLAndContainerSources(c *cfg, client *cntClient.Client, cnrSrc containerCore.Source) (*morphContainerReader, *morphContainerWriter) {
|
2021-08-30 11:16:41 +00:00
|
|
|
eACLFetcher := &morphEACLFetcher{
|
2023-03-24 07:35:41 +00:00
|
|
|
w: client,
|
2021-08-30 11:16:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cnrRdr := new(morphContainerReader)
|
2021-09-08 17:24:16 +00:00
|
|
|
|
|
|
|
cnrWrt := &morphContainerWriter{
|
2023-03-24 07:35:41 +00:00
|
|
|
neoClient: client,
|
2021-09-08 17:24:16 +00:00
|
|
|
}
|
2021-07-29 15:57:53 +00:00
|
|
|
|
2022-08-16 11:59:30 +00:00
|
|
|
if c.cfgMorph.cacheTTL <= 0 {
|
2021-08-30 11:16:41 +00:00
|
|
|
c.cfgObject.eaclSource = eACLFetcher
|
|
|
|
cnrRdr.eacl = eACLFetcher
|
|
|
|
c.cfgObject.cnrSource = cnrSrc
|
2023-08-24 12:27:24 +00:00
|
|
|
cnrRdr.src = cnrSrc
|
2023-03-24 07:35:41 +00:00
|
|
|
cnrRdr.lister = client
|
2021-07-29 15:57:53 +00:00
|
|
|
} else {
|
2021-08-30 11:16:41 +00:00
|
|
|
// use RPC node as source of Container contract items (with caching)
|
2024-09-27 09:39:43 +00:00
|
|
|
c.cfgObject.cnrSource = cnrSrc
|
|
|
|
if c.cfgMorph.containerCacheSize > 0 {
|
|
|
|
containerCache := newCachedContainerStorage(cnrSrc, c.cfgMorph.cacheTTL, c.cfgMorph.containerCacheSize)
|
|
|
|
|
|
|
|
subscribeToContainerCreation(c, func(e event.Event) {
|
|
|
|
ev := e.(containerEvent.PutSuccess)
|
|
|
|
|
|
|
|
// read owner of the created container in order to update the reading cache.
|
|
|
|
// TODO: use owner directly from the event after neofs-contract#256 will become resolved
|
|
|
|
// but don't forget about the profit of reading the new container and caching it:
|
|
|
|
// creation success are most commonly tracked by polling GET op.
|
|
|
|
cnr, err := cnrSrc.Get(ev.ID)
|
|
|
|
if err == nil {
|
|
|
|
containerCache.containerCache.set(ev.ID, cnr, nil)
|
|
|
|
} else {
|
|
|
|
// unlike removal, we expect successful receive of the container
|
|
|
|
// after successful creation, so logging can be useful
|
|
|
|
c.log.Error(logs.FrostFSNodeReadNewlyCreatedContainerAfterTheNotification,
|
|
|
|
zap.Stringer("id", ev.ID),
|
|
|
|
zap.Error(err),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.log.Debug(logs.FrostFSNodeContainerCreationEventsReceipt,
|
2022-08-12 10:25:04 +00:00
|
|
|
zap.Stringer("id", ev.ID),
|
|
|
|
)
|
2024-09-27 09:39:43 +00:00
|
|
|
})
|
2022-08-12 10:25:04 +00:00
|
|
|
|
2024-09-27 09:39:43 +00:00
|
|
|
subscribeToContainerRemoval(c, func(e event.Event) {
|
|
|
|
ev := e.(containerEvent.DeleteSuccess)
|
|
|
|
containerCache.handleRemoval(ev.ID)
|
|
|
|
c.log.Debug(logs.FrostFSNodeContainerRemovalEventsReceipt,
|
|
|
|
zap.Stringer("id", ev.ID),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
c.cfgObject.cnrSource = containerCache
|
|
|
|
}
|
2022-08-11 14:48:16 +00:00
|
|
|
|
2024-09-27 09:39:43 +00:00
|
|
|
cachedEACLStorage := newCachedEACLStorage(eACLFetcher, c.cfgMorph.cacheTTL)
|
2021-09-08 13:40:23 +00:00
|
|
|
c.cfgObject.eaclSource = cachedEACLStorage
|
|
|
|
|
2023-11-17 06:05:46 +00:00
|
|
|
cnrRdr.lister = client
|
2021-08-30 11:16:41 +00:00
|
|
|
cnrRdr.eacl = c.cfgObject.eaclSource
|
2023-08-24 12:27:24 +00:00
|
|
|
cnrRdr.src = c.cfgObject.cnrSource
|
2021-07-29 15:57:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-24 07:35:41 +00:00
|
|
|
return cnrRdr, cnrWrt
|
|
|
|
}
|
2021-02-01 12:41:00 +00:00
|
|
|
|
2022-10-17 12:03:55 +00:00
|
|
|
// addContainerNotificationHandler adds handler that will be executed synchronously.
|
2021-02-01 12:33:58 +00:00
|
|
|
func addContainerNotificationHandler(c *cfg, sTyp string, h event.Handler) {
|
|
|
|
typ := event.TypeFromString(sTyp)
|
|
|
|
|
|
|
|
if c.cfgContainer.subscribers == nil {
|
|
|
|
c.cfgContainer.subscribers = make(map[event.Type][]event.Handler, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.cfgContainer.subscribers[typ] = append(c.cfgContainer.subscribers[typ], h)
|
|
|
|
}
|
|
|
|
|
2022-10-17 12:03:55 +00:00
|
|
|
// addContainerAsyncNotificationHandler adds handler that will be executed asynchronously via container workerPool.
|
2021-04-14 14:31:49 +00:00
|
|
|
func addContainerAsyncNotificationHandler(c *cfg, sTyp string, h event.Handler) {
|
|
|
|
addContainerNotificationHandler(
|
|
|
|
c,
|
|
|
|
sTyp,
|
|
|
|
event.WorkerPoolHandler(
|
|
|
|
c.cfgContainer.workerPool,
|
|
|
|
h,
|
|
|
|
c.log,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-08-11 13:24:26 +00:00
|
|
|
// stores already registered parsers of the notification events thrown by Container contract.
|
|
|
|
// MUST NOT be used concurrently.
|
|
|
|
var mRegisteredParsersContainer = make(map[string]struct{})
|
|
|
|
|
|
|
|
// registers event parser by name once. MUST NOT be called concurrently.
|
|
|
|
func registerEventParserOnceContainer(c *cfg, name string, p event.NotificationParser) {
|
|
|
|
if _, ok := mRegisteredParsersContainer[name]; !ok {
|
|
|
|
setContainerNotificationParser(c, name, p)
|
|
|
|
mRegisteredParsersContainer[name] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// subscribes to successful container creation. Provided handler is called asynchronously
|
|
|
|
// on corresponding routine pool. MUST NOT be called concurrently with itself and other
|
|
|
|
// similar functions.
|
|
|
|
func subscribeToContainerCreation(c *cfg, h event.Handler) {
|
|
|
|
const eventNameContainerCreated = "PutSuccess"
|
|
|
|
registerEventParserOnceContainer(c, eventNameContainerCreated, containerEvent.ParsePutSuccess)
|
|
|
|
addContainerAsyncNotificationHandler(c, eventNameContainerCreated, h)
|
|
|
|
}
|
|
|
|
|
|
|
|
// like subscribeToContainerCreation but for removal.
|
|
|
|
func subscribeToContainerRemoval(c *cfg, h event.Handler) {
|
|
|
|
const eventNameContainerRemoved = "DeleteSuccess"
|
|
|
|
registerEventParserOnceContainer(c, eventNameContainerRemoved, containerEvent.ParseDeleteSuccess)
|
|
|
|
addContainerAsyncNotificationHandler(c, eventNameContainerRemoved, h)
|
|
|
|
}
|
|
|
|
|
2021-08-12 15:24:17 +00:00
|
|
|
func setContainerNotificationParser(c *cfg, sTyp string, p event.NotificationParser) {
|
2021-02-01 12:33:58 +00:00
|
|
|
typ := event.TypeFromString(sTyp)
|
|
|
|
|
|
|
|
if c.cfgContainer.parsers == nil {
|
2021-08-12 15:24:17 +00:00
|
|
|
c.cfgContainer.parsers = make(map[event.Type]event.NotificationParser, 1)
|
2021-02-01 12:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
c.cfgContainer.parsers[typ] = p
|
|
|
|
}
|
|
|
|
|
2021-02-01 12:29:35 +00:00
|
|
|
func (c *cfg) PublicKey() []byte {
|
2021-06-11 10:55:11 +00:00
|
|
|
return nodeKeyFromNetmap(c)
|
2021-02-01 12:29:35 +00:00
|
|
|
}
|
|
|
|
|
2021-09-06 12:17:14 +00:00
|
|
|
func (c *cfg) IsLocalKey(key []byte) bool {
|
|
|
|
return bytes.Equal(key, c.PublicKey())
|
|
|
|
}
|
|
|
|
|
2021-06-22 16:00:00 +00:00
|
|
|
func (c *cfg) IterateAddresses(f func(string) bool) {
|
|
|
|
c.iterateNetworkAddresses(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *cfg) NumberOfAddresses() int {
|
|
|
|
return c.addressNum()
|
2021-02-01 12:29:35 +00:00
|
|
|
}
|
|
|
|
|
2022-09-26 12:34:01 +00:00
|
|
|
func (c *cfg) ExternalAddresses() []string {
|
|
|
|
return c.cfgNodeInfo.localInfo.ExternalAddresses()
|
|
|
|
}
|
|
|
|
|
2021-08-30 11:16:41 +00:00
|
|
|
// implements interface required by container service provided by morph executor.
|
|
|
|
type morphContainerReader struct {
|
2022-09-08 10:32:25 +00:00
|
|
|
eacl containerCore.EACLSource
|
2021-08-30 11:16:41 +00:00
|
|
|
|
2023-08-24 12:27:24 +00:00
|
|
|
src containerCore.Source
|
2021-08-30 11:16:41 +00:00
|
|
|
|
|
|
|
lister interface {
|
2024-02-06 17:29:39 +00:00
|
|
|
ContainersOf(*user.ID) ([]cid.ID, error)
|
2021-08-30 11:16:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-22 10:55:31 +00:00
|
|
|
func (x *morphContainerReader) Get(id cid.ID) (*containerCore.Container, error) {
|
2023-08-24 12:27:24 +00:00
|
|
|
return x.src.Get(id)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (x *morphContainerReader) DeletionInfo(id cid.ID) (*containerCore.DelInfo, error) {
|
|
|
|
return x.src.DeletionInfo(id)
|
2021-08-30 11:16:41 +00:00
|
|
|
}
|
|
|
|
|
2022-06-22 10:55:31 +00:00
|
|
|
func (x *morphContainerReader) GetEACL(id cid.ID) (*containerCore.EACL, error) {
|
2021-08-30 11:16:41 +00:00
|
|
|
return x.eacl.GetEACL(id)
|
|
|
|
}
|
|
|
|
|
2024-02-06 17:29:39 +00:00
|
|
|
func (x *morphContainerReader) ContainersOf(id *user.ID) ([]cid.ID, error) {
|
|
|
|
return x.lister.ContainersOf(id)
|
2021-08-30 11:16:41 +00:00
|
|
|
}
|
2021-09-08 13:40:23 +00:00
|
|
|
|
2021-09-08 17:24:16 +00:00
|
|
|
type morphContainerWriter struct {
|
2022-01-31 13:34:01 +00:00
|
|
|
neoClient *cntClient.Client
|
2021-09-08 17:24:16 +00:00
|
|
|
}
|
2021-09-08 13:40:23 +00:00
|
|
|
|
2022-06-22 10:55:31 +00:00
|
|
|
func (m morphContainerWriter) Put(cnr containerCore.Container) (*cid.ID, error) {
|
2022-08-12 10:25:04 +00:00
|
|
|
return cntClient.Put(m.neoClient, cnr)
|
2021-09-08 13:40:23 +00:00
|
|
|
}
|
|
|
|
|
2021-09-08 17:24:16 +00:00
|
|
|
func (m morphContainerWriter) Delete(witness containerCore.RemovalWitness) error {
|
2022-04-15 05:52:24 +00:00
|
|
|
return cntClient.Delete(m.neoClient, witness)
|
2021-09-08 13:40:23 +00:00
|
|
|
}
|