Skip to content
This repository has been archived by the owner on Dec 18, 2020. It is now read-only.

Removed hardcode from protokube logic. Fixes #15. #46

Merged
merged 1 commit into from
Apr 11, 2017
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
4 changes: 2 additions & 2 deletions docs/development/vsphere-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Please note that dns-controller has also been modified to support vSphere. You c
Execute following command to launch cluster.

```bash
.build/dist/darwin/amd64/kops create cluster kubernetes.skydns.local --cloud=vsphere --zones=${AWS_REGION}a --dns-zone=skydns.local --networking=flannel
.build/dist/darwin/amd64/kops create cluster kubernetes.skydns.local --cloud=vsphere --zones=vmware-zone --dns-zone=skydns.local --networking=flannel
--vsphere-server=10.160.97.44 --vsphere-datacenter=VSAN-DC --vsphere-resource-pool=VSAN-Cluster --vsphere-datastore=vsanDatastore --dns private --vsphere-coredns-server=http://10.192.217.24:2379 --image="ubuntu_16_04"
```

Expand All @@ -102,7 +102,7 @@ Use .build/dist/linux/amd64/kops if working on a linux machine, instead of mac.
**Notes**

1. ```clustername``` should end with **skydns.local**. Example: ```kubernetes.cluster.skydns.local```.
2. ```zones``` should end with ```a```. Example: ```us-west-2a``` or as the above command sets ```--zones=${AWS_REGION}a```.
2. For ```zones``` any string will do, for now. It's only getting used for the construction of names of various entities. But it's a mandatory argument.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if any strings will do, why not have a default ? Or, are you saying it will be mandatory in the future when the string will have meaning ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From kops (aws and gce) point of view default zone doesn't mean anything. I am hoping that we would be able to come up with some meaningful mapping for zone names. If not, later we can think about making it a default. But yes... for now any string will do.

3. Make sure following parameters have these values,
* ```--dns-zone=skydns.local```
* ```--networking=flannel```
Expand Down
1 change: 1 addition & 0 deletions pkg/model/vspheremodel/autoscalinggroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
VM: createVmTask,
IG: ig,
BootstrapScript: b.BootstrapScript,
EtcdClusters: b.Cluster.Spec.EtcdClusters,
}
attachISOTask.BootstrapScript.AddAwsEnvironmentVariables = true

Expand Down
116 changes: 68 additions & 48 deletions protokube/pkg/protokube/vsphere_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,26 @@ package protokube

import (
"errors"
"fmt"
"github.com/golang/glog"
"io/ioutil"
"k8s.io/kops/upup/pkg/fi/cloudup/vsphere"
"net"
"os/exec"
"runtime"
"strings"
)

const EtcdDataKey = "01"
const EtcdDataVolPath = "/mnt/master-" + EtcdDataKey
const EtcdEventKey = "02"
const EtcdEventVolPath = "/mnt/master-" + EtcdEventKey

// TODO Use lsblk or counterpart command to find the actual device details.
const LocalDeviceForDataVol = "/dev/sdb1"
const LocalDeviceForEventsVol = "/dev/sdc1"
const VolumeMetaDataFile = "/vol-metadata/metadata.json"
const VolStatusValue = "attached"
const EtcdNodeName = "a"
const EtcdClusterName = "main"
const EtcdEventsClusterName = "events"

type VSphereVolumes struct {
// Dummy property. Not getting used any where for now.
paths map[string]string
}
type VSphereVolumes struct{}

var _ Volumes = &VSphereVolumes{}
var machineIp net.IP

func NewVSphereVolumes() (*VSphereVolumes, error) {
vsphereVolumes := &VSphereVolumes{
paths: make(map[string]string),
}
vsphereVolumes.paths[EtcdDataKey] = EtcdDataVolPath
vsphereVolumes.paths[EtcdEventKey] = EtcdEventVolPath
vsphereVolumes := &VSphereVolumes{}
return vsphereVolumes, nil
}

Expand All @@ -60,49 +49,80 @@ func (v *VSphereVolumes) FindVolumes() ([]*Volume, error) {
attachedTo = ip.String()
}

// etcd data volume and etcd cluster spec.
{
etcdClusters, err := getVolMetadata()

if err != nil {
return nil, err
}

for _, etcd := range etcdClusters {
mountPoint := vsphere.GetMountPoint(etcd.VolumeId)
localDevice, err := getDevice(mountPoint)
if err != nil {
return nil, err
}
vol := &Volume{
ID: EtcdDataKey,
LocalDevice: LocalDeviceForDataVol,
ID: etcd.VolumeId,
LocalDevice: localDevice,
AttachedTo: attachedTo,
Mountpoint: EtcdDataVolPath,
Mountpoint: mountPoint,
Status: VolStatusValue,
Info: VolumeInfo{
Description: EtcdClusterName,
Description: etcd.EtcdClusterName,
},
}

etcdSpec := &EtcdClusterSpec{
ClusterKey: EtcdClusterName,
NodeName: EtcdNodeName,
NodeNames: []string{EtcdNodeName},
ClusterKey: etcd.EtcdClusterName,
NodeName: etcd.EtcdNodeName,
}

var nodeNames []string
for _, member := range etcd.Members {
nodeNames = append(nodeNames, member.Name)
}
etcdSpec.NodeNames = nodeNames
vol.Info.EtcdClusters = []*EtcdClusterSpec{etcdSpec}
volumes = append(volumes, vol)
}
glog.V(4).Infof("Found volumes: %v", volumes)
return volumes, nil
}

// etcd events volume and etcd events cluster spec.
{
vol := &Volume{
ID: EtcdEventKey,
LocalDevice: LocalDeviceForEventsVol,
AttachedTo: attachedTo,
Mountpoint: EtcdEventVolPath,
Status: VolStatusValue,
Info: VolumeInfo{
Description: EtcdEventsClusterName,
},
func getDevice(mountPoint string) (string, error) {
if runtime.GOOS == "linux" {
cmd := "lsblk"
arg := "-l"
out, err := exec.Command(cmd, arg).Output()
if err != nil {
return "", err
}
etcdSpec := &EtcdClusterSpec{
ClusterKey: EtcdEventsClusterName,
NodeName: EtcdNodeName,
NodeNames: []string{EtcdNodeName},

if Containerized {
mountPoint = PathFor(mountPoint)
}
vol.Info.EtcdClusters = []*EtcdClusterSpec{etcdSpec}
volumes = append(volumes, vol)
lines := strings.Split(string(out), "\n")
for _, line := range lines {
if strings.Contains(line, mountPoint) {
lsblkOutput := strings.Split(line, " ")
glog.V(4).Infof("Found device: %v ", lsblkOutput[0])
return "/dev/" + lsblkOutput[0], nil
}
}
} else {
return "", fmt.Errorf("Failed to find device. OS %v is not supported for vSphere.", runtime.GOOS)
}
glog.Infof("Found volumes: %v", volumes)
return volumes, nil
return "", fmt.Errorf("No device has been mounted on mountPoint %v.", mountPoint)
}

func getVolMetadata() ([]vsphere.VolumeMetadata, error) {
rawData, err := ioutil.ReadFile(PathFor(VolumeMetaDataFile))

if err != nil {
return nil, err
}

return vsphere.UnmarshalVolumeMetadata(string(rawData))
}

func (v *VSphereVolumes) AttachVolume(volume *Volume) error {
Expand Down
66 changes: 66 additions & 0 deletions upup/pkg/fi/cloudup/vsphere/vsphere_volume_metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vsphere

import (
"encoding/json"
"strconv"
)

type VolumeMetadata struct {
// EtcdClusterName is the name of the etcd cluster (main, events etc)
EtcdClusterName string `json:"etcdClusterName,omitempty"`
// EtcdNodeName is the name of a node in etcd cluster for which this volume will be used
EtcdNodeName string `json:"etcdNodeName,omitempty"`
// EtcdMember stores the configurations for each member of the cluster
Members []EtcdMemberSpec `json:"etcdMembers,omitempty"`
// Volume id
VolumeId string `json:"volumeId,omitempty"`
}

type EtcdMemberSpec struct {
// Name is the name of the member within the etcd cluster
Name string `json:"name,omitempty"`
InstanceGroup string `json:"instanceGroup,omitempty"`
}

func MarshalVolumeMetadata(v []VolumeMetadata) (string, error) {
metadata, err := json.Marshal(v)
if err != nil {
return "", err
}

return string(metadata), nil
}

func UnmarshalVolumeMetadata(text string) ([]VolumeMetadata, error) {
var v []VolumeMetadata
err := json.Unmarshal([]byte(text), &v)
return v, err
}

func GetVolumeId(i int) string {
return "0" + strconv.Itoa(i)
}

/*
* GetMountPoint will return the mount point where the volume is expected to be mounted.
* This path would be /mnt/master-<volumeId>, eg: /mnt/master-01.
*/
func GetMountPoint(volumeId string) string {
return "/mnt/master-" + volumeId
}
69 changes: 65 additions & 4 deletions upup/pkg/fi/cloudup/vspheretasks/attachiso.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type AttachISO struct {
VM *VirtualMachine
IG *kops.InstanceGroup
BootstrapScript *model.BootstrapScript
EtcdClusters []*kops.EtcdClusterSpec
}

var _ fi.HasName = &AttachISO{}
Expand Down Expand Up @@ -111,7 +112,7 @@ func (_ *AttachISO) RenderVSphere(t *vsphere.VSphereAPITarget, a, e, changes *At
return nil
}

func createUserData(startupStr string, dir string, dnsServer string, vmUUID string) error {
func createUserData(changes *AttachISO, startupStr string, dir string, dnsServer string, vmUUID string) error {
// Update the startup script to add the extra spaces for
// indentation when copied to the user-data file.
strArray := strings.Split(startupStr, "\n")
Expand Down Expand Up @@ -140,17 +141,76 @@ func createUserData(startupStr string, dir string, dnsServer string, vmUUID stri
vmUUIDStr := " " + vmUUID + "\n"
data = strings.Replace(data, "$VM_UUID", vmUUIDStr, -1)

data, err = createVolumeScript(changes, data)
if err != nil {
return err
}

userDataFile := filepath.Join(dir, "user-data")
glog.V(4).Infof("User data file content: %s", data)

if err := ioutil.WriteFile(userDataFile, []byte(data), 0644); err != nil {
if err = ioutil.WriteFile(userDataFile, []byte(data), 0644); err != nil {
glog.Errorf("Unable to write user-data into file %s", userDataFile)
return err
}

return nil
}

func createVolumeScript(changes *AttachISO, data string) (string, error) {
if changes.IG.Spec.Role != kops.InstanceGroupRoleMaster {
return strings.Replace(data, "$VOLUME_SCRIPT", " No volume metadata needed for "+string(changes.IG.Spec.Role)+".", -1), nil
}

volsString, err := getVolMetadata(changes)

if err != nil {
return "", err
}

return strings.Replace(data, "$VOLUME_SCRIPT", " "+volsString, -1), nil
}

func getVolMetadata(changes *AttachISO) (string, error) {
var volsMetadata []vsphere.VolumeMetadata

// Creating vsphere.VolumeMetadata using clusters EtcdClusterSpec
for i, etcd := range changes.EtcdClusters {
volMetadata := vsphere.VolumeMetadata{}
volMetadata.EtcdClusterName = etcd.Name
volMetadata.VolumeId = vsphere.GetVolumeId(i + 1)

var members []vsphere.EtcdMemberSpec
var thisNode string
for _, member := range etcd.Members {
if *member.InstanceGroup == changes.IG.Name {
thisNode = member.Name
}
etcdMember := vsphere.EtcdMemberSpec{
Name: member.Name,
InstanceGroup: *member.InstanceGroup,
}
members = append(members, etcdMember)
}

if thisNode == "" {
return "", fmt.Errorf("Failed to construct volume metadata for %v InstanceGroup.", changes.IG.Name)
}

volMetadata.EtcdNodeName = thisNode
volMetadata.Members = members
volsMetadata = append(volsMetadata, volMetadata)
}

glog.V(4).Infof("Marshaling master vol metadata : %v", volsMetadata)
volsString, err := vsphere.MarshalVolumeMetadata(volsMetadata)
glog.V(4).Infof("Marshaled master vol metadata: %v", volsString)
if err != nil {
return "", err
}
return volsString, nil
}

func createMetaData(dir string, vmName string) error {
data := strings.Replace(metaDataTemplate, "$INSTANCE_ID", uuid.NewUUID().String(), -1)
data = strings.Replace(data, "$LOCAL_HOST_NAME", vmName, -1)
Expand All @@ -165,8 +225,9 @@ func createMetaData(dir string, vmName string) error {
return nil
}

func createISO(changes *AttachISO, startupStr string, dir string, dnsServer string, vmUUID string) (string, error) {
err := createUserData(startupStr, dir, dnsServer, vmUUID)
func createISO(changes *AttachISO, startupStr string, dir string, dnsServer, vmUUID string) (string, error) {
err := createUserData(changes, startupStr, dir, dnsServer, vmUUID)

if err != nil {
return "", err
}
Expand Down
5 changes: 5 additions & 0 deletions upup/pkg/fi/cloudup/vspheretasks/cloud_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ $VM_UUID
owner: root:root
path: /root/vm_uuid
permissions: "0644"
- content: |
$VOLUME_SCRIPT
owner: root:root
path: /vol-metadata/metadata.json
permissions: "0644"

runcmd:
- bash /root/update_dns.sh 2>&1 > /var/log/update_dns.log
Expand Down