diff --git a/pkg/repository/errors.go b/pkg/repository/errors.go new file mode 100644 index 00000000..449acc64 --- /dev/null +++ b/pkg/repository/errors.go @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package repository is the database abstraction implementing repository design pattern +package repository + +// OperationError when cannot perform a given operation on database (SET, GET or DELETE) +type OperationError struct { + operation string +} + +func (err *OperationError) Error() string { + return "Could not perform the " + err.operation + " operation." +} + +// DownError when its not a redis.Nil response, in this case the database is down +type DownError struct{} + +func (dbe *DownError) Error() string { + return "Database is down" +} + +// CreateDatabaseError when cannot perform set on database +type CreateDatabaseError struct{} + +func (err *CreateDatabaseError) Error() string { + return "Could not create Databse" +} + +// NotImplementedDatabaseError when user tries to create a not implemented database +type NotImplementedDatabaseError struct { + database string +} + +func (err *NotImplementedDatabaseError) Error() string { + return err.database + " not implemented" +} diff --git a/pkg/repository/memory.go b/pkg/repository/memory.go new file mode 100644 index 00000000..e4bdb927 --- /dev/null +++ b/pkg/repository/memory.go @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package repository is the database abstraction implementing repository design pattern +package repository + +import "sync" + +type memoryDatabase struct { + data map[string]string + lock sync.RWMutex +} + +func NewMemoryDatabase() *memoryDatabase { + return &memoryDatabase{ + data: make(map[string]string), + lock: &sync.RWMutex{}, + } +} + +func (repo *memoryDatabase) Set(key string, value string) (string, error) { + repo.lock.RLock() + defer repo.lock.RUnlock() + repo.data[key] = value +} + +func (repo *memoryDatabase) Get(key string) (string, error) { + repo.lock.RLock() + defer repo.lock.RUnlock() + value, err := repo.data[key] + if err != nil { + // TODO: use our own errors + return nil, err + } + return value, nil +} + +func (repo *memoryDatabase) Delete(key string) (string, error) { + repo.lock.RLock() + defer repo.lock.RUnlock() + delete(repo.data, key) +} diff --git a/pkg/repository/models.go b/pkg/repository/models.go new file mode 100644 index 00000000..20cab0b8 --- /dev/null +++ b/pkg/repository/models.go @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package repository is the database abstraction implementing repository design pattern +package repository + +import ( + "encoding/binary" + "net" + + pb "github.com/opiproject/opi-api/network/evpn-gw/v1alpha1/gen/go" +) + +type Vrf struct { + Vni int + LoopbackIp net.IPNet + VtepIp net.IPNet +} + +func NewVrf(in pb.Vrf) *Vrf { + myip := make(net.IP, 4) + binary.BigEndian.PutUint32(myip, in.Vrf.Spec.LoopbackIpPrefix.Addr.GetV4Addr()) + lip := net.IPNet{IP: myip, Mask: net.CIDRMask(int(in.Vrf.Spec.LoopbackIpPrefix.Len), 32)} + return &Vrf{Vni: in.Spec.Vni, LoopbackIp: lip} +} + +func (s *Vrf) ToPb() (*pb.Vrf, error) { + return &pb.Vrf{Spec: nil, Status: nil} +} + +type Svi struct { + VrfRefKey string + LogicalBridgeRefKey string + MacAddress net.HardwareAddr + GwIp net.IPNet +} + +func NewSvi(in pb.Svi) *Svi { + mac := net.HardwareAddr(in.Spec.MacAddress[:]) + myip := make(net.IP, 4) + binary.BigEndian.PutUint32(myip, in.Svi.Spec.GwIpPrefix.Addr.GetV4Addr()) + gip := net.IPNet{IP: myip, Mask: net.CIDRMask(int(in.Svi.Spec.GwIpPrefix.Len), 32)} + return &Svi{VrfRefKey: in.Spec.Vrf, LogicalBridgeRefKey: in.Spec.LogicalBridge, MacAddress: mac, GwIp: gip} +} + +func (s *Svi) ToPb() (*pb.Svi, error) { + return &pb.Svi{Spec: nil, Status: nil} +} diff --git a/pkg/repository/redis.go b/pkg/repository/redis.go new file mode 100644 index 00000000..0e2c0c0e --- /dev/null +++ b/pkg/repository/redis.go @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package repository is the database abstraction implementing repository design pattern +package repository + +import "github.com/go-redis/redis" + +type redisDatabase struct { + client *redis.Client +} + +func NewRedisDatabase() (Database, error) { + // TODO: pass address + client := redis.NewClient(&redis.Options{ + Addr: "redis:6379", + Password: "", // no password set + DB: 0, // use default DB + }) + _, err := client.Ping().Result() // makes sure database is connected + if err != nil { + return nil, &CreateDatabaseError{} + } + return &redisDatabase{client: client}, nil +} + +func (r *redisDatabase) Set(key string, value string) (string, error) { + _, err := r.client.Set(key, value, 0).Result() + if err != nil { + return generateError("set", err) + } + return key, nil +} + +func (r *redisDatabase) Get(key string) (string, error) { + value, err := r.client.Get(key).Result() + if err != nil { + return generateError("get", err) + } + return value, nil +} + +func (r *redisDatabase) Delete(key string) (string, error) { + _, err := r.client.Del(key).Result() + if err != nil { + return generateError("delete", err) + } + return key, nil +} + +func generateError(operation string, err error) (string, error) { + if err == redis.Nil { + return "", &OperationError{operation} + } + return "", &DownError{} +} diff --git a/pkg/repository/repository.go b/pkg/repository/repository.go new file mode 100644 index 00000000..a0a84d1d --- /dev/null +++ b/pkg/repository/repository.go @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2022-2023 Dell Inc, or its subsidiaries. + +// Package repository is the database abstraction implementing repository design pattern +package repository + +// Database abstraction +type Database interface { + Set(key string, value string) (string, error) + Get(key string) (string, error) + Delete(key string) (string, error) +} + +// Factory pattern to create new Database +func Factory(databaseImplementation string) (Database, error) { + switch databaseImplementation { + case "redis": + return NewRedisDatabase() + case "memory": + return NewMemoryDatabase() + default: + return nil, &NotImplementedDatabaseError{databaseImplementation} + } +}