Skip to content

Commit

Permalink
create IPAM once
Browse files Browse the repository at this point in the history
Signed-off-by: Oleg Vasilev <[email protected]>
  • Loading branch information
Omrigan committed Feb 21, 2025
1 parent e49c357 commit 40bd3bb
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 74 deletions.
10 changes: 10 additions & 0 deletions neonvm-controller/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ import (
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"

Check failure on line 46 in neonvm-controller/cmd/main.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not properly formatted (gci)
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/klog/v2"

vmv1 "github.com/neondatabase/autoscaling/neonvm/apis/neonvm/v1"
"github.com/neondatabase/autoscaling/pkg/neonvm/controllers"
"github.com/neondatabase/autoscaling/pkg/neonvm/ipam"
"github.com/neondatabase/autoscaling/pkg/util"
)

Expand Down Expand Up @@ -197,6 +199,13 @@ func main() {
FailingRefreshInterval: failingRefreshInterval,
AtMostOnePod: atMostOnePod,
DefaultCPUScalingMode: defaultCpuScalingMode,
NADConfig: controllers.GetNADConfig(),
}

ipam, err := ipam.New(rc.NADConfig.IPAMName, rc.NADConfig.IPAMNamespace)
if err != nil {
setupLog.Error(err, "unable to create ipam")
os.Exit(1)
}

vmReconciler := &controllers.VMReconciler{
Expand All @@ -205,6 +214,7 @@ func main() {
Recorder: mgr.GetEventRecorderFor("virtualmachine-controller"),
Config: rc,
Metrics: reconcilerMetrics,
IPAM: ipam,
}
vmReconcilerMetrics, err := vmReconciler.SetupWithManager(mgr)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions pkg/neonvm/controllers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,7 @@ type ReconcilerConfig struct {
AtMostOnePod bool
// DefaultCPUScalingMode is the default CPU scaling mode that will be used for VMs with empty spec.cpuScalingMode
DefaultCPUScalingMode vmv1.CpuScalingMode

// NADConfig is the configuration for the Network Attachment Definitions
NADConfig *NADConfig
}
2 changes: 2 additions & 0 deletions pkg/neonvm/controllers/functests/vm_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ var _ = Describe("VirtualMachine controller", func() {
FailingRefreshInterval: 1 * time.Minute,
AtMostOnePod: false,
DefaultCPUScalingMode: vmv1.CpuScalingModeQMP,
NADConfig: nil,
},
IPAM: nil,
}

_, err = virtualmachineReconciler.Reconcile(ctx, reconcile.Request{
Expand Down
93 changes: 22 additions & 71 deletions pkg/neonvm/controllers/vm_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type VMReconciler struct {
Scheme *runtime.Scheme
Recorder record.EventRecorder
Config *ReconcilerConfig
IPAM *ipam.IPAM

Metrics ReconcilerMetrics `exhaustruct:"optional"`
}
Expand Down Expand Up @@ -238,27 +239,7 @@ func (r *VMReconciler) doFinalizerOperationsForVirtualMachine(ctx context.Contex

// Release overlay IP address
if vm.Spec.ExtraNetwork != nil {
// Create IPAM object
nadName, err := nadIpamName()
if err != nil {
// ignore error
log.Error(err, "ignored error")
return
}
nadNamespace, err := nadIpamNamespace()
if err != nil {
// ignore error
log.Error(err, "ignored error")
return
}
ipam, err := ipam.New(ctx, nadName, nadNamespace)
if err != nil {
// ignore error
log.Error(err, "ignored error")
return
}
defer ipam.Close()
ip, err := ipam.ReleaseIP(ctx, types.NamespacedName{Name: vm.Name, Namespace: vm.Namespace})
ip, err := r.IPAM.ReleaseIP(ctx, types.NamespacedName{Name: vm.Name, Namespace: vm.Namespace})
if err != nil {
// ignore error
log.Error(err, "fail to release IP, error ignored")
Expand Down Expand Up @@ -347,23 +328,7 @@ func (r *VMReconciler) acquireOverlayIP(ctx context.Context, vm *vmv1.VirtualMac
}

log := log.FromContext(ctx)

// Create IPAM object
nadName, err := nadIpamName()
if err != nil {
return err
}
nadNamespace, err := nadIpamNamespace()
if err != nil {
return err
}
ipam, err := ipam.New(ctx, nadName, nadNamespace)
if err != nil {
log.Error(err, "failed to create IPAM")
return err
}
defer ipam.Close()
ip, err := ipam.AcquireIP(ctx, types.NamespacedName{Name: vm.Name, Namespace: vm.Namespace})
ip, err := r.IPAM.AcquireIP(ctx, types.NamespacedName{Name: vm.Name, Namespace: vm.Namespace})
if err != nil {
log.Error(err, "fail to acquire IP")
return err
Expand Down Expand Up @@ -1712,15 +1677,7 @@ func podSpec(
if len(vm.Spec.ExtraNetwork.MultusNetwork) > 0 { // network specified in spec
nadNetwork = vm.Spec.ExtraNetwork.MultusNetwork
} else { // get network from env variables
nadName, err := nadRunnerName()
if err != nil {
return nil, err
}
nadNamespace, err := nadRunnerNamespace()
if err != nil {
return nil, err
}
nadNetwork = fmt.Sprintf("%s/%s", nadNamespace, nadName)
nadNetwork = fmt.Sprintf("%s/%s", config.NADConfig.IPAMNamespace, config.NADConfig.IPAMName)
}
pod.ObjectMeta.Annotations[nadapiv1.NetworkAttachmentAnnot] = fmt.Sprintf("%s@%s", nadNetwork, vm.Spec.ExtraNetwork.Interface)
}
Expand Down Expand Up @@ -1770,33 +1727,27 @@ func (r *VMReconciler) tryUpdateVM(ctx context.Context, vm *vmv1.VirtualMachine)
return r.Update(ctx, vm)
}

// return Network Attachment Definition name with IPAM settings
func nadIpamName() (string, error) {
return getEnvVarValue("NAD_IPAM_NAME")
type NADConfig struct {
IPAMName string
IPAMNamespace string
RunnerName string
RunnerNamespace string
}

// return Network Attachment Definition namespace with IPAM settings
func nadIpamNamespace() (string, error) {
return getEnvVarValue("NAD_IPAM_NAMESPACE")
}

// return Network Attachment Definition name for second interface in Runner
func nadRunnerName() (string, error) {
return getEnvVarValue("NAD_RUNNER_NAME")
}

// return Network Attachment Definition namespace for second interface in Runner
func nadRunnerNamespace() (string, error) {
return getEnvVarValue("NAD_RUNNER_NAMESPACE")
}

// return env variable value
func getEnvVarValue(envVarName string) (string, error) {
value, found := os.LookupEnv(envVarName)
if !found {
return "", fmt.Errorf("unable to find %s environment variable", envVarName)
func GetNADConfig() *NADConfig {
getVar := func(envVarName string) string {
value, ok := os.LookupEnv(envVarName)
if !ok {
panic(fmt.Errorf("unable to find %s environment variable", envVarName))
}
return value
}
return &NADConfig{
IPAMName: getVar("NAD_IPAM_NAME"),
IPAMNamespace: getVar("NAD_IPAM_NAMESPACE"),
RunnerName: getVar("NAD_RUNNER_NAME"),
RunnerNamespace: getVar("NAD_RUNNER_NAMESPACE"),
}
return value, nil
}

// sshKeygen generates a pair of public and private keys using the ed25519
Expand Down
2 changes: 2 additions & 0 deletions pkg/neonvm/controllers/vm_controller_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ func newTestParams(t *testing.T) *testParams {
FailingRefreshInterval: time.Minute,
AtMostOnePod: false,
DefaultCPUScalingMode: vmv1.CpuScalingModeQMP,
NADConfig: nil,
},
Metrics: testReconcilerMetrics,
IPAM: nil,
}

return params
Expand Down
1 change: 1 addition & 0 deletions pkg/neonvm/controllers/vmmigration_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func newMigrationTestParams(t *testing.T) *migrationTestParams {
FailingRefreshInterval: time.Minute,
AtMostOnePod: false,
DefaultCPUScalingMode: vmv1.CpuScalingModeQMP,
NADConfig: nil,
},
Metrics: testReconcilerMetrics,
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/neonvm/ipam/demo/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func main() {
ctx := log.IntoContext(context.Background(), logger)

// Create IPAM object
ipam, err := ipam.New(ctx, *nadName, *nadNs)
ipam, err := ipam.New(*nadName, *nadNs)
if err != nil {
logger.Error(err, "failed to create IPAM")
os.Exit(1)
Expand Down
4 changes: 2 additions & 2 deletions pkg/neonvm/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (i *IPAM) RunCleanup(ctx context.Context, namespace string) error {
}

// New returns a new IPAM object with ipam config and k8s/crd clients
func New(ctx context.Context, nadName string, nadNamespace string) (*IPAM, error) {
func New(nadName string, nadNamespace string) (*IPAM, error) {
// get Kubernetes client config
cfg, err := config.GetConfig()
if err != nil {
Expand All @@ -113,7 +113,7 @@ func New(ctx context.Context, nadName string, nadNamespace string) (*IPAM, error
}

// read network-attachment-definition from Kubernetes
nad, err := kClient.nadClient.K8sCniCncfIoV1().NetworkAttachmentDefinitions(nadNamespace).Get(ctx, nadName, metav1.GetOptions{})
nad, err := kClient.nadClient.K8sCniCncfIoV1().NetworkAttachmentDefinitions(nadNamespace).Get(context.Background(), nadName, metav1.GetOptions{})
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 40bd3bb

Please sign in to comment.