Skip to content

Commit

Permalink
Enable golang CPI implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
OBoehrer committed Oct 18, 2024
1 parent e150880 commit c54a6b4
Show file tree
Hide file tree
Showing 308 changed files with 46,777 additions and 129 deletions.
1 change: 0 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,3 @@ If you still want to run manual tests (e.g. in order to validate your use case)
```

- Deploy a BOSH Director using your CPI release (see [bosh.io](http://bosh.io/docs/init-openstack.html#create-manifest))

3 changes: 0 additions & 3 deletions jobs/openstack_cpi_golang/spec
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ templates:
cpi.erb: bin/cpi
cpi.json.erb: config/cpi.json
cacert.pem.erb: config/cacert.pem
cpi-golang.erb: bin/cpi-golang
cpi-ruby.erb: bin/cpi-ruby

packages:
- openstack_cpi_golang
- bosh_openstack_cpi
- openstack-ruby-3.1

properties:
openstack.auth_url:
Expand Down
39 changes: 20 additions & 19 deletions jobs/openstack_cpi_golang/templates/cpi.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@

set -e

BOSH_JOBS_DIR=${BOSH_JOBS_DIR:-/var/vcap/jobs}
GOLANG_CPI_CALLS=("info")
REGEXP="\"method\":\"([^\"]*)\""
<% if_p('env.http_proxy') do |http_proxy| %>
export HTTP_PROXY="<%= http_proxy %>"
export http_proxy="<%= http_proxy %>"
<% end %>

<% if_p('env.https_proxy') do |https_proxy| %>
export HTTPS_PROXY="<%= https_proxy %>"
export https_proxy="<%= https_proxy %>"
<% end %>

STDIN=$(cat /dev/stdin)
<% if_p('env.no_proxy') do |no_proxy| %>
export NO_PROXY="<%= no_proxy %>"
export no_proxy="<%= no_proxy %>"
<% end %>

BOSH_PACKAGES_DIR=${BOSH_PACKAGES_DIR:-/var/vcap/packages}
BOSH_JOBS_DIR=${BOSH_JOBS_DIR:-/var/vcap/jobs}

if [[ ${STDIN} =~ ${REGEXP} ]]
then
for element in "${GOLANG_CPI_CALLS[@]}"
do
if [[ $element == ${BASH_REMATCH[1]} ]]
then
${BOSH_JOBS_DIR}/openstack_cpi_golang/bin/cpi-golang <<< ${STDIN}
exit $?
fi
done
${BOSH_JOBS_DIR}/openstack_cpi_golang/bin/cpi-ruby <<< ${STDIN}
else
echo "input stream is not defining a method"
exit 1
fi
platform=`uname | tr '[:upper:]' '[:lower:]'`
exec ${BOSH_PACKAGES_DIR}/openstack_cpi_golang/bin/cpi-${platform} \
-configFile=${BOSH_JOBS_DIR}/openstack_cpi_golang/config/cpi.json \
-caCert=${BOSH_JOBS_DIR}/openstack_cpi_golang/config/cacert.pem
2 changes: 1 addition & 1 deletion src/openstack_cpi_golang/.tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
golang 1.21.3
golang 1.22.6
39 changes: 39 additions & 0 deletions src/openstack_cpi_golang/cpi/compute/availbility_zone_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package compute

import (
"math/rand"
"time"

"github.com/cloudfoundry/bosh-openstack-cpi-release/src/openstack_cpi_golang/cpi/properties"
)

//counterfeiter:generate . AvailabilityZoneProvider
type AvailabilityZoneProvider interface {
GetAvailabilityZones(cloudProperties properties.CreateVM) []string
}

type availabilityZoneProvider struct {
}

func NewAvailabilityZoneProvider() availabilityZoneProvider {
return availabilityZoneProvider{}
}

func (a availabilityZoneProvider) GetAvailabilityZones(cloudProperties properties.CreateVM) []string {

if len(cloudProperties.AvailabilityZones) > 0 {
return a.shuffleAZs(cloudProperties)
}

return []string{cloudProperties.AvailabilityZone}
}

func (a availabilityZoneProvider) shuffleAZs(cloudProperties properties.CreateVM) []string {
shuffledZones := cloudProperties.AvailabilityZones
r := rand.New(rand.NewSource(time.Now().UnixNano()))

r.Shuffle(len(shuffledZones), func(i, j int) {
shuffledZones[i], shuffledZones[j] = shuffledZones[j], shuffledZones[i]
})
return shuffledZones
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package compute_test

import (
"github.com/cloudfoundry/bosh-openstack-cpi-release/src/openstack_cpi_golang/cpi/compute"
"github.com/cloudfoundry/bosh-openstack-cpi-release/src/openstack_cpi_golang/cpi/properties"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("AvailabilityZoneProvider", func() {
Context("GetAvailabilityZones", func() {

var cloudProps properties.CreateVM

Context("with cloud property availability_zones", func() {

BeforeEach(func() {
cloudProps = properties.CreateVM{}
cloudProps.AvailabilityZone = ""
})

It("returns a single availability zone", func() {
cloudProps.AvailabilityZones = []string{"z1"}
zone := compute.NewAvailabilityZoneProvider().
GetAvailabilityZones(cloudProps)

Expect(len(zone)).To(Equal(1))
Expect(zone).To(ContainElement("z1"))
})

It("returns a single availability zone", func() {
cloudProps.AvailabilityZones = []string{"z1", "z2", "z3"}
zone := compute.NewAvailabilityZoneProvider().
GetAvailabilityZones(cloudProps)

Expect(len(zone)).To(Equal(3))
Expect(zone).To(ContainElements("z1", "z2", "z3"))
})
})

Context("with cloud property availability_zone", func() {

BeforeEach(func() {
cloudProps = properties.CreateVM{}
cloudProps.AvailabilityZones = []string{}
})

It("returns a single availability zone", func() {
cloudProps.AvailabilityZone = "z1"
zone := compute.NewAvailabilityZoneProvider().
GetAvailabilityZones(cloudProps)

Expect(len(zone)).To(Equal(1))
Expect(zone).To(ContainElement("z1"))
})
})
})
})
123 changes: 123 additions & 0 deletions src/openstack_cpi_golang/cpi/compute/compute_facade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package compute

import (
"github.com/cloudfoundry/bosh-openstack-cpi-release/src/openstack_cpi_golang/cpi/utils"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/availabilityzones"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach"
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
"github.com/gophercloud/gophercloud/pagination"
)

type ServerWithAZ struct {
servers.Server
availabilityzones.ServerAvailabilityZoneExt
}

//counterfeiter:generate . ComputeFacade
type ComputeFacade interface {
CreateServer(client utils.ServiceClient, opts servers.CreateOptsBuilder) (*servers.Server, error)

DeleteServer(client utils.RetryableServiceClient, serverID string) error

RebootServer(client utils.ServiceClient, serverID string, opts servers.RebootOptsBuilder) error

GetServer(client utils.RetryableServiceClient, serverID string) (*servers.Server, error)

GetServerWithAZ(client utils.RetryableServiceClient, serverID string) (*ServerWithAZ, error)

ListFlavors(client utils.RetryableServiceClient, opts flavors.ListOpts) (pagination.Page, error)

ExtractFlavors(page pagination.Page) ([]flavors.Flavor, error)

GetOSKeyPair(client utils.RetryableServiceClient, keyPairName string, ops keypairs.GetOpts) (*keypairs.KeyPair, error)

GetServerMetadata(client utils.RetryableServiceClient, serverID string) (map[string]string, error)

UpdateServer(client utils.ServiceClient, serverID string, opt servers.UpdateOptsBuilder) (*servers.Server, error)

UpdateServerMetadata(client utils.ServiceClient, serverID string, opts servers.UpdateMetadataOptsBuilder) (map[string]string, error)

DeleteServerMetaData(client *gophercloud.ServiceClient, serverID string, key string) error

AttachVolume(client *gophercloud.ServiceClient, serverID string, opts volumeattach.CreateOptsBuilder) (*volumeattach.VolumeAttachment, error)

DetachVolume(client *gophercloud.ServiceClient, serverID string, volumeID string) error

ListVolumeAttachments(client *gophercloud.ServiceClient, serverID string) ([]volumeattach.VolumeAttachment, error)
}

type computeFacade struct {
}

func NewComputeFacade() computeFacade {
return computeFacade{}
}

func (c computeFacade) CreateServer(client utils.ServiceClient, opts servers.CreateOptsBuilder) (*servers.Server, error) {
return servers.Create(client, opts).Extract()
}

func (c computeFacade) DeleteServer(client utils.RetryableServiceClient, serverID string) error {
return servers.Delete(client, serverID).ExtractErr()
}

func (c computeFacade) RebootServer(client utils.ServiceClient, serverID string, opts servers.RebootOptsBuilder) error {
return servers.Reboot(client, serverID, opts).ExtractErr()
}

func (c computeFacade) GetServer(client utils.RetryableServiceClient, serverID string) (*servers.Server, error) {
return servers.Get(client, serverID).Extract()
}

func (c computeFacade) GetServerWithAZ(client utils.RetryableServiceClient, serverID string) (*ServerWithAZ, error) {
var serverWithAz ServerWithAZ
err := servers.Get(client, serverID).ExtractInto(&serverWithAz)
return &serverWithAz, err
}

func (c computeFacade) ListFlavors(client utils.RetryableServiceClient, opts flavors.ListOpts) (pagination.Page, error) {
return flavors.ListDetail(client, opts).AllPages()
}

func (c computeFacade) ExtractFlavors(page pagination.Page) ([]flavors.Flavor, error) {
return flavors.ExtractFlavors(page)
}

func (c computeFacade) GetOSKeyPair(client utils.RetryableServiceClient, keyPairName string, opts keypairs.GetOpts) (*keypairs.KeyPair, error) {
return keypairs.Get(client, keyPairName, opts).Extract()
}

func (c computeFacade) GetServerMetadata(client utils.RetryableServiceClient, serverID string) (map[string]string, error) {
return servers.Metadata(client, serverID).Extract()
}

func (c computeFacade) UpdateServer(client utils.ServiceClient, serverID string, opts servers.UpdateOptsBuilder) (*servers.Server, error) {
return servers.Update(client, serverID, opts).Extract()
}

func (c computeFacade) UpdateServerMetadata(client utils.ServiceClient, serverID string, opts servers.UpdateMetadataOptsBuilder) (map[string]string, error) {
return servers.UpdateMetadata(client, serverID, opts).Extract()
}

func (c computeFacade) DeleteServerMetaData(client *gophercloud.ServiceClient, serverID string, key string) error {
return servers.DeleteMetadatum(client, serverID, key).ExtractErr()
}

func (c computeFacade) AttachVolume(client *gophercloud.ServiceClient, serverID string, opts volumeattach.CreateOptsBuilder) (*volumeattach.VolumeAttachment, error) {
return volumeattach.Create(client, serverID, opts).Extract()
}

func (c computeFacade) DetachVolume(client *gophercloud.ServiceClient, serverID string, volumeID string) error {
return volumeattach.Delete(client, serverID, volumeID).ExtractErr()
}

func (c computeFacade) ListVolumeAttachments(client *gophercloud.ServiceClient, serverID string) ([]volumeattach.VolumeAttachment, error) {
page, err := volumeattach.List(client, serverID).AllPages()
if err != nil {
return nil, err
}
return volumeattach.ExtractVolumeAttachments(page)
}
Loading

0 comments on commit c54a6b4

Please sign in to comment.