Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add dhcp network support #196

Merged
merged 1 commit into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 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 @@ -84,13 +85,20 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
return nil, err
}

dhcpClient, err := b.config.DHCPClient(ctx, b.config.ServiceInstanceID)
if err != nil {
return nil, err
}

var steps []multistep.Step

steps = append(steps,
&StepImageBaseImage{
Source: b.config.Source,
},
&StepCreateNetwork{},
&StepCreateNetwork{
DHCPNetwork: b.config.DHCPNetwork,
},
&StepCreateInstance{
InstanceName: b.config.InstanceName,
KeyPairName: b.config.KeyPairName,
Expand All @@ -117,6 +125,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
state.Put("jobClient", jobClient)
state.Put("instanceClient", instanceClient)
state.Put("networkClient", networkClient)
state.Put("dhcpClient", dhcpClient)

// Run!
b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui)
Expand Down
2 changes: 2 additions & 0 deletions builder/powervs/builder.hcl2spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
62 changes: 59 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 @@ -17,9 +20,11 @@ var (
// for determining the SSH address of the instance.
func SSHHost() func(multistep.StateBag) (string, error) {
return func(state multistep.StateBag) (string, error) {
ui := state.Get("ui").(packersdk.Ui)
ui.Message("Fetching IP for machine")
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 +39,60 @@ func SSHHost() func(multistep.StateBag) (string, error) {
if host != "" {
return host, nil
}

dhcpServerID, ok := state.GetOk("dhcpServerID")
if !ok {
// if the dhcpServerID is not set, dont try to fetch IP from DHCP server, instead wait for address to get populated.
ui.Message("Machine IP is not yet found, Trying again")
time.Sleep(sshHostSleepDuration)
continue
}
dhcpClient := state.Get("dhcpClient").(*instance.IBMPIDhcpClient)
ui.Message("Getting Instance IP from DHCP server")

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.Message("Failed to get network attached to VM, Trying again")
time.Sleep(sshHostSleepDuration)
continue
}

dhcpServerDetails, err := dhcpClient.Get(dhcpServerID.(string))
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 from DHCP server lease, Trying again")
time.Sleep(sshHostSleepDuration)
}

return "", errors.New("couldn't determine address for instance")
}
}
Expand Down
82 changes: 79 additions & 3 deletions builder/powervs/step_create_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,48 @@ 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"),
}
ui.Message("Creating Network")
net, err := networkClient.Create(netBody)
if err != nil {
ui.Error(fmt.Sprintf("failed to create network: %v", err))
Expand All @@ -46,11 +66,67 @@ func (s *StepCreateNetwork) Cleanup(state multistep.StateBag) {
ui := state.Get("ui").(packersdk.Ui)

ui.Say("Deleting the Network")

if s.DHCPNetwork {
ui.Message("Deleting DHCP server")
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 error: %v", dhcpServerID, err.Error()))
}
ui.Message("Successfully deleted DHCP server")
return
}
networkClient := state.Get("networkClient").(*instance.IBMPINetworkClient)
net := state.Get("network").(*models.Network)
err := networkClient.Delete(*net.NetworkID)
if err != nil {
ui.Error(fmt.Sprintf(
"Error cleaning up network. Please delete the network manually: %s", *net.Name))
}
ui.Message("Successfully deleted network")
}

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

dhcpServer, err := dhcpClient.Create(&models.DHCPServerCreate{})
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
ui.Message("DHCP server in active state")
break
}
if time.Since(startTime) > DHCPServerActiveTimeOut {
return fmt.Errorf("error DHCP server did not become active even after %f min", DHCPServerActiveTimeOut.Minutes())
}
ui.Message("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
}
Loading
Loading