Skip to content

Commit

Permalink
Add dhcp network support
Browse files Browse the repository at this point in the history
  • Loading branch information
Karthik-K-N committed Apr 23, 2024
1 parent 6d09135 commit 532653f
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 6 deletions.
5 changes: 4 additions & 1 deletion builder/powervs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package powervs

import (
"context"

"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer-plugin-sdk/common"
"github.com/hashicorp/packer-plugin-sdk/communicator"
Expand Down Expand Up @@ -90,7 +91,9 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
&StepImageBaseImage{
Source: b.config.Source,
},
&StepCreateNetwork{},
&StepCreateNetwork{
DHCPNetwork: b.config.DHCPNetwork,
},
&StepCreateInstance{
InstanceName: b.config.InstanceName,
KeyPairName: b.config.KeyPairName,
Expand Down
8 changes: 8 additions & 0 deletions builder/powervs/common/access_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,11 @@ func (c *AccessConfig) JobClient(ctx context.Context, id string) (*instance.IBMP
}
return instance.NewIBMPIJobClient(ctx, session, id), nil
}

func (c *AccessConfig) DHCPClient(ctx context.Context, id string) (*instance.IBMPIDhcpClient, error) {
session, err := c.Session()
if err != nil {
return nil, err
}
return instance.NewIBMPIDhcpClient(ctx, session, id), nil
}
1 change: 1 addition & 0 deletions builder/powervs/common/run_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type CaptureCOS struct {
type RunConfig struct {
InstanceName string `mapstructure:"instance_name" required:"true"`
KeyPairName string `mapstructure:"key_pair_name" required:"true"`
DHCPNetwork bool `mapstructure:"dhcp_network" required:"false"`
Source Source `mapstructure:"source" required:"true"`
Capture Capture `mapstructure:"capture" required:"true"`

Expand Down
56 changes: 53 additions & 3 deletions builder/powervs/common/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package common

import (
"errors"
"fmt"
"time"

"github.com/IBM-Cloud/power-go-client/clients/instance"
"github.com/IBM-Cloud/power-go-client/power/models"
"github.com/hashicorp/packer-plugin-sdk/multistep"
"time"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)

var (
Expand All @@ -19,7 +22,7 @@ func SSHHost() func(multistep.StateBag) (string, error) {
return func(state multistep.StateBag) (string, error) {
instanceClient := state.Get("instanceClient").(*instance.IBMPIInstanceClient)
host := ""
const tries = 15
const tries = 25
for j := 0; j <= tries; j++ {
i := state.Get("instance").(*models.PVMInstance)
in, err := instanceClient.Get(*i.PvmInstanceID)
Expand All @@ -34,9 +37,56 @@ func SSHHost() func(multistep.StateBag) (string, error) {
if host != "" {
return host, nil
}

ui := state.Get("ui").(packersdk.Ui)
ui.Say("Get Instance IP from DHCP server")

dhcpClient := state.Get("dhcpClient").(*instance.IBMPIDhcpClient)

net := state.Get("network").(*models.Network)
networkID := net.NetworkID

var pvmNetwork *models.PVMInstanceNetwork
for _, network := range in.Networks {
if network.NetworkID == *networkID {
pvmNetwork = network
ui.Message("Found network attached to VM")
}
}

if pvmNetwork == nil {
ui.Error("Failed to get network attached to VM")
return "", err
}

dhcpServerID := state.Get("dhcpServerID").(string)

dhcpServerDetails, err := dhcpClient.Get(dhcpServerID)
if err != nil {
ui.Error(fmt.Sprintf("Failed to get DHCP server details: %v", err))
return "", err
}

if dhcpServerDetails == nil {
ui.Error(fmt.Sprintf("DHCP server details is nil, DHCPServerID: %s", dhcpServerID))
return "", err
}

var internalIP string
for _, lease := range dhcpServerDetails.Leases {
if *lease.InstanceMacAddress == pvmNetwork.MacAddress {
ui.Message(fmt.Sprintf("Found internal ip for VM from DHCP lease IP %s", *lease.InstanceIP))
internalIP = *lease.InstanceIP
break
}
}
if internalIP != "" {
return internalIP, nil
}

ui.Message("Machine IP is not yet found")
time.Sleep(sshHostSleepDuration)
}

return "", errors.New("couldn't determine address for instance")
}
}
Expand Down
81 changes: 79 additions & 2 deletions builder/powervs/step_create_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,44 @@ package powervs
import (
"context"
"fmt"
"time"

"github.com/IBM-Cloud/power-go-client/clients/instance"
"github.com/IBM-Cloud/power-go-client/power/models"
"github.com/IBM/go-sdk-core/v5/core"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
)

const (
// DHCPServerActiveTimeOut is time to wait for DHCP Server status to become active.
DHCPServerActiveTimeOut = 15 * time.Minute
// DHCPServerInterval is time to sleep before checking DHCP Server status.
DHCPServerInterval = 1 * time.Minute
)

type StepCreateNetwork struct {
doCleanup bool
DHCPNetwork bool
doCleanup bool
}

func (s *StepCreateNetwork) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packersdk.Ui)
ui.Say("Creating Instance")

networkClient := state.Get("networkClient").(*instance.IBMPINetworkClient)

// If CreateDHCPNetwork is set, Create DHCP network.
if s.DHCPNetwork {
ui.Say("Creating DHCP network")
if err := s.createDHCPNetwork(state); err != nil {
ui.Error(fmt.Sprintf("failed to create DHCP network: %v", err))
return multistep.ActionHalt
}
s.doCleanup = true
return multistep.ActionContinue
}

ui.Say("Creating network")
netBody := &models.NetworkCreate{
DNSServers: []string{"8.8.8.8", "9.9.9.9"},
Type: core.StringPtr("pub-vlan"),
Expand All @@ -46,6 +67,16 @@ func (s *StepCreateNetwork) Cleanup(state multistep.StateBag) {
ui := state.Get("ui").(packersdk.Ui)

ui.Say("Deleting the Network")

if s.DHCPNetwork {
dhcpServerID := state.Get("dhcpServerID").(string)
dhcpClient := state.Get("dhcpClient").(*instance.IBMPIDhcpClient)

if err := dhcpClient.Delete(dhcpServerID); err != nil {
ui.Error(fmt.Sprintf("Error cleaning up DHCP server. Please delete the DHCP server manually: %s", dhcpServerID))
}
return
}
networkClient := state.Get("networkClient").(*instance.IBMPINetworkClient)
net := state.Get("network").(*models.Network)
err := networkClient.Delete(*net.NetworkID)
Expand All @@ -54,3 +85,49 @@ func (s *StepCreateNetwork) Cleanup(state multistep.StateBag) {
"Error cleaning up network. Please delete the network manually: %s", *net.Name))
}
}

func (s *StepCreateNetwork) createDHCPNetwork(state multistep.StateBag) error {
ui := state.Get("ui").(packersdk.Ui)
dhcpClient := state.Get("dhcpClient").(*instance.IBMPIDhcpClient)

dhcpServerCreateParams := models.DHCPServerCreate{
Name: core.StringPtr("packerdhcpnetwork"),
}

dhcpServer, err := dhcpClient.Create(&dhcpServerCreateParams)
if err != nil {
return fmt.Errorf("error failed to create DHCP server: %v", err)
}

if dhcpServer.ID == nil {
return fmt.Errorf("error created DHCP server ID is nil")
}
state.Put("dhcpServerID", *dhcpServer.ID)

startTime := time.Now()
var networkID string
for {
dhcpServerDetails, err := dhcpClient.Get(*dhcpServer.ID)
if err != nil {
return err
}
if dhcpServerDetails.Network != nil && dhcpServerDetails.Network.ID != nil {
networkID = *dhcpServerDetails.Network.ID
break
}
if time.Since(startTime) > DHCPServerActiveTimeOut {
return fmt.Errorf("error DHCP server did not become active even after %f min", DHCPServerActiveTimeOut.Minutes())
}
ui.Say("Wating for DHCP server to become active")
time.Sleep(DHCPServerInterval)
}
ui.Say("Fetching network details")
networkClient := state.Get("networkClient").(*instance.IBMPINetworkClient)
// fetch the dhcp network details and store it for future usage.
net, err := networkClient.Get(networkID)
if err != nil {
return fmt.Errorf("error fetching network details with network id %s error: %v", networkID, err)
}
state.Put("network", net)
return nil
}

0 comments on commit 532653f

Please sign in to comment.