2. write out cert files
This commit is contained in:
Anthony Howe 2016-10-06 06:35:27 -07:00
Родитель cf14d79db0
Коммит 1a9333629f
10 изменённых файлов: 433 добавлений и 122 удалений

Просмотреть файл

@ -6,6 +6,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"strings"
"./api/vlabs"
@ -77,6 +78,63 @@ func prettyPrintArmTemplate(template string) (string, error) {
return template, nil
}
func writeArtifacts(acsCluster *vlabs.AcsCluster, artifactsDir string) error {
if len(artifactsDir) == 0 {
artifactsDir = fmt.Sprintf("k8s-%s", acsCluster.OrchestratorProfile.ClusterID)
}
//b, err := json.Marshal(acsCluster)
b, err := json.MarshalIndent(acsCluster, "", " ")
if err != nil {
return err
}
if e := saveFile(artifactsDir, "apimodel.json", b); e != nil {
return e
}
if e := saveFileString(artifactsDir, "ca.key", acsCluster.OrchestratorProfile.GetCAPrivateKey()); e != nil {
return e
}
if e := saveFileString(artifactsDir, "ca.crt", acsCluster.OrchestratorProfile.CaCertificate); e != nil {
return e
}
if e := saveFileString(artifactsDir, "apiserver.key", acsCluster.OrchestratorProfile.ApiServerPrivateKey); e != nil {
return e
}
if e := saveFileString(artifactsDir, "apiserver.crt", acsCluster.OrchestratorProfile.ApiServerCertificate); e != nil {
return e
}
if e := saveFileString(artifactsDir, "client.key", acsCluster.OrchestratorProfile.ClientPrivateKey); e != nil {
return e
}
if e := saveFileString(artifactsDir, "client.crt", acsCluster.OrchestratorProfile.ClientCertificate); e != nil {
return e
}
return nil
}
func saveFileString(dir string, file string, data string) error {
return saveFile(dir, file, []byte(data))
}
func saveFile(dir string, file string, data []byte) error {
if _, err := os.Stat(dir); os.IsNotExist(err) {
if e := os.Mkdir(dir, 0700); e != nil {
return fmt.Errorf("error creating directory '%s': %s", dir, e.Error())
}
}
path := path.Join(dir, file)
if err := ioutil.WriteFile(path, []byte(data), 0600); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "wrote %s\n", path)
return nil
}
func usage(errs ...error) {
for _, err := range errs {
fmt.Fprintf(os.Stderr, "error: %s\n\n", err.Error())
@ -90,6 +148,8 @@ func usage(errs ...error) {
var templateDirectory = flag.String("templateDirectory", "./parts", "directory containing base template files")
var noPrettyPrint = flag.Bool("noPrettyPrint", false, "do not pretty print output")
var noArtifacts = flag.Bool("noArtifacts", false, "does not generate artifacts (api model, json, cert files)")
var artifactsDir = flag.String("artifacts", "", "directory where artifacts will be written")
func main() {
var acsCluster *vlabs.AcsCluster
@ -124,7 +184,8 @@ func main() {
os.Exit(1)
}
if err = tgen.SetAcsClusterDefaults(acsCluster); err != nil {
certsGenerated := false
if certsGenerated, err = tgen.SetAcsClusterDefaults(acsCluster); err != nil {
fmt.Fprintf(os.Stderr, "error while setting defaults %s: %s", jsonFile, err.Error())
os.Exit(1)
}
@ -134,6 +195,13 @@ func main() {
os.Exit(1)
}
if certsGenerated && !*noArtifacts {
if err = writeArtifacts(acsCluster, *artifactsDir); err != nil {
fmt.Fprintf(os.Stderr, "error writing artifacts %s", err.Error())
os.Exit(1)
}
}
if !*noPrettyPrint {
if template, err = prettyPrintArmTemplate(template); err != nil {
fmt.Fprintf(os.Stderr, "error pretty printing template %s", err.Error())

Просмотреть файл

@ -18,6 +18,7 @@ type OrchestratorProfile struct {
CaCertificate string `json:"caCertificate,omitempty"`
ClientCertificate string `json:"clientCertificate,omitempty"`
ClientPrivateKey string `json:"clientPrivateKey,omitempty"`
ClusterID string `json:"clusterid,omitempty"`
// caPrivateKey is an internal field only set if generation required
caPrivateKey string
}

Просмотреть файл

@ -31,16 +31,6 @@ func (o *OrchestratorProfile) Validate() error {
return fmt.Errorf("Service principal and secret is not required for orchestrator %s", o.OrchestratorType)
}
if o.OrchestratorType == Kubernetes {
if len(o.ApiServerCertificate) > 0 || len(o.ApiServerPrivateKey) > 0 || len(o.CaCertificate) > 0 || len(o.ClientCertificate) > 0 || len(o.ClientPrivateKey) > 0 {
return fmt.Errorf("API, CA, and Client certs are required for orchestrator %s", o.OrchestratorType)
}
} else {
if len(o.ApiServerCertificate) > 0 || len(o.ApiServerPrivateKey) > 0 || len(o.CaCertificate) > 0 || len(o.ClientCertificate) > 0 || len(o.ClientPrivateKey) > 0 {
return fmt.Errorf("API, CA, and Client certs are not required for orchestrator %s", o.OrchestratorType)
}
}
return nil
}

Просмотреть файл

@ -0,0 +1,178 @@
#cloud-config
# { { { param } } }
runcmd:
- /usr/bin/curl -sSL --retry 12 --retry-delay 10 https://get.docker.com/ > /tmp/install-docker
- /bin/bash -c "/bin/bash /tmp/install-docker"
- systemctl restart docker
- systemctl restart kubelet
write_files:
- path: "/etc/systemd/system/docker.service.d/clear_mount_propagation_flags.conf"
permissions: "0644"
owner: "root"
content: |
[Service]
MountFlags=shared
- path: "/etc/systemd/system/docker.service.d/overlay.conf"
permissions: "0644"
owner: "root"
content: |
[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// --storage-driver=overlay
- path: "/etc/kubernetes/azure.json"
permissions: "0644"
owner: "root"
content: |
{
"tenantId": "{{{tenantID}}}",
"subscriptionId": "{{{subscriptionId}}}",
"aadClientId": "{{{servicePrincipalClientId}}}",
"aadClientSecret": "{{{servicePrincipalClientSecret}}}",
"resourceGroup": "{{{resourceGroup}}}",
"location": "{{{location}}}",
"subnetName": "{{{subnetName}}}",
"securityGroupName": "{{{nsgName}}}",
"vnetName": "{{{virtualNetworkName}}}",
"routeTableName": "{{{routeTableName}}}"
}
- path: "/etc/kubernetes/certs/ca.crt"
permissions: "0644"
encoding: "base64"
owner: "root"
content: |
{{{caCertificate}}}
- path: "/etc/kubernetes/certs/apiserver.crt"
permissions: "0644"
encoding: "base64"
owner: "root"
content: |
{{{apiserverCertificate}}}
- path: "/etc/kubernetes/certs/apiserver.key"
permissions: "0644"
encoding: "base64"
owner: "root"
content: |
{{{apiserverPrivateKey}}}
- path: "/etc/kubernetes/certs/client.crt"
permissions: "0644"
encoding: "base64"
owner: "root"
content: |
{{{clientCertificate}}}
- path: "/etc/kubernetes/certs/client.key"
permissions: "0644"
encoding: "base64"
owner: "root"
content: |
{{{clientPrivateKey}}}
- path: "/var/lib/kubelet/kubeconfig"
permissions: "0644"
owner: "root"
content: |
apiVersion: v1
kind: Config
clusters:
- name: localcluster
cluster:
certificate-authority: /etc/kubernetes/certs/ca.crt
server: https://{{{masterPrivateIp}}}:443
users:
- name: client
user:
client-certificate: /etc/kubernetes/certs/client.crt
client-key: /etc/kubernetes/certs/client.key
contexts:
- context:
cluster: localcluster
user: client
name: localclustercontext
current-context: localclustercontext
- path: /etc/kubernetes/manifests/node.yaml
permissions: "0644"
owner: "root"
content: |
apiVersion: "v1"
kind: "Pod"
metadata:
name: "k8s-node"
namespace: "kube-system"
spec:
hostNetwork: true
containers:
- name: "kube-proxy"
image: "{{{kubernetesHyperkubeSpec}}}"
command:
- "/hyperkube"
- "proxy"
- "--kubeconfig=/var/lib/kubelet/kubeconfig"
- "--proxy-mode=iptables"
- "--v=2"
securityContext:
privileged: true
volumeMounts:
- name: "etc-kubernetes"
mountPath: "/etc/kubernetes"
- name: "var-lib-kubelet"
mountPath: "/var/lib/kubelet"
volumes:
- name: "etc-kubernetes"
hostPath:
path: "/etc/kubernetes"
- name: "var-lib-kubelet"
hostPath:
path: "/var/lib/kubelet"
- path: "/etc/systemd/system/kubelet.service"
permissions: "0644"
owner: "root"
content: |
[Unit]
Description=Kubelet
Requires=docker.service
After=docker.service
[Service]
Restart=always
ExecStartPre=/bin/mkdir -p /var/lib/kubelet
ExecStartPre=/bin/mount --bind /var/lib/kubelet /var/lib/kubelet
ExecStartPre=/bin/mount --make-shared /var/lib/kubelet
ExecStart=/usr/bin/docker run \
--net=host \
--pid=host \
--privileged \
--volume=/:/rootfs:ro \
--volume=/sys:/sys:ro \
--volume=/var/run:/var/run:rw \
--volume=/var/lib/docker/:/var/lib/docker:rw \
--volume=/var/lib/kubelet/:/var/lib/kubelet:shared \
--volume=/var/log/containers/:/var/log/containers:rw \
--volume=/etc/kubernetes/:/etc/kubernetes/:rw \
{{{kubernetesHyperkubeSpec}}} \
/hyperkube kubelet \
--api-servers="https://{{{masterPrivateIp}}}:443" \
--kubeconfig=/var/lib/kubelet/kubeconfig \
--address=0.0.0.0 \
--allow-privileged=true \
--enable-server \
--enable-debugging-handlers \
--config=/etc/kubernetes/manifests \
--cluster-dns={{{kubeDnsServiceIP}}} \
--cluster-domain=cluster.local \
--cloud-provider=azure \
--cloud-config=/etc/kubernetes/azure.json \
--hairpin-mode=promiscuous-bridge \
--network-plugin=kubenet \
--reconcile-cidr \
--v=2
ExecStop=/usr/bin/docker stop -t 2 kubelet

Просмотреть файл

@ -50,6 +50,7 @@
},
"type": "Microsoft.Storage/storageAccounts"
},
{{if .HasDisks}}
{
"apiVersion": "[variables('apiVersionStorage')]",
"copy": {
@ -66,10 +67,77 @@
},
"type": "Microsoft.Storage/storageAccounts"
},
{{end}}
{
"apiVersion": "[variables('apiVersionDefault')]",
"location": "[variables('location')]",
"name": "[variables('{{.Name}}AvailabilitySet')]",
"properties": {},
"type": "Microsoft.Compute/availabilitySets"
},
{
"apiVersion": "[variables('apiVersionDefault')]",
"copy": {
"count": "[variables('{{.Name}}Count')]",
"name": "vmLoopNode"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName'))]",
{{if .HasDisks}}
"[concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('dataStorageAccountPrefixSeed')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}DataAccountName'))]",
{{end}}
"[concat('Microsoft.Network/networkInterfaces/', variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex())]",
"[concat('Microsoft.Compute/availabilitySets/', variables('{{.Name}}AvailabilitySet'))]"
],
"location": "[variables('location')]",
"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex())]",
"properties": {
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets',variables('{{.Name}}AvailabilitySet'))]"
},
"hardwareProfile": {
"vmSize": "[variables('{{.Name}}VMSize')]"
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('{{.Name}}VMNamePrefix'), 'nic-', copyIndex()))]"
}
]
},
"osProfile": {
"adminUsername": "[variables('username')]",
"computername": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex())]",
{{GetKubernetesAgentCustomData}}
"linuxConfiguration": {
"disablePasswordAuthentication": "true",
"ssh": {
"publicKeys": [
{
"keyData": "[parameters('sshRSAPublicKey')]",
"path": "[variables('sshKeyPath')]"
}
]
}
}
},
"storageProfile": {
{{GetDataDisks .}}
"imageReference": {
"offer": "[variables('osImageOffer')]",
"publisher": "[variables('osImagePublisher')]",
"sku": "[variables('osImageSKU')]",
"version": "[variables('osImageVersion')]"
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"name": "[concat(variables('{{.Name}}VMNamePrefix'), copyIndex(),'-osdisk')]",
"vhd": {
"uri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/',variables('storageAccountPrefixes')[mod(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('storageAccountPrefixes')[div(add(div(copyIndex(),variables('maxVMsPerStorageAccount')),variables('{{.Name}}StorageAccountOffset')),variables('storageAccountPrefixesCount'))],variables('{{.Name}}AccountName')),variables('apiVersionStorage')).primaryEndpoints.blob,'osdisk/', variables('{{.Name}}VMNamePrefix'), copyIndex(), '-osdisk.vhd')]"
}
}
}
},
"type": "Microsoft.Compute/virtualMachines"
}

Просмотреть файл

Просмотреть файл

@ -1,6 +1,5 @@
#cloud-config
# [ [ [ var ] ] ]
# { { { param } } }
packages:

Просмотреть файл

@ -1,40 +1,33 @@
"apiServerCertificate": {
"defaultValue": "{{.OrchestratorProfile.ApiServerCertificate}}",
"defaultValue": "{{Base64 .OrchestratorProfile.ApiServerCertificate}}",
"metadata": {
"description": "The AD Tenant Id"
},
"type": "string"
},
"apiServerPrivateKey": {
"defaultValue": "{{.OrchestratorProfile.ApiServerPrivateKey}}",
"defaultValue": "{{Base64 .OrchestratorProfile.ApiServerPrivateKey}}",
"metadata": {
"description": "User name for the Linux Virtual Machines (SSH or Password)."
},
"type": "securestring"
},
"caCertificate": {
"defaultValue": "{{.OrchestratorProfile.CaCertificate}}",
"defaultValue": "{{Base64 .OrchestratorProfile.CaCertificate}}",
"metadata": {
"description": "The certificate authority certificate"
},
"type": "string"
},
"caPrivateKey": {
"defaultValue": "{{.OrchestratorProfile.GetCAPrivateKey}}",
"metadata": {
"description": "The certificate authority private key, this is only generated once and not used in this file, save this file for future updates"
},
"type": "string"
},
"clientCertificate": {
"defaultValue": "{{.OrchestratorProfile.ClientCertificate}}",
"defaultValue": "{{Base64 .OrchestratorProfile.ClientCertificate}}",
"metadata": {
"description": "The client certificate used to communicate with the master"
},
"type": "string"
},
"clientPrivateKey": {
"defaultValue": "{{.OrchestratorProfile.ClientPrivateKey}}",
"defaultValue": "{{Base64 .OrchestratorProfile.ClientPrivateKey}}",
"metadata": {
"description": "The client private key used to communicate with the master"
},

Просмотреть файл

@ -1,24 +1,42 @@
package templategenerator
import (
"encoding/base64"
"fmt"
"hash/fnv"
"math/rand"
"net"
"./../api/vlabs"
"./../util"
)
// SetAcsClusterDefaults for an AcsCluster
func SetAcsClusterDefaults(a *vlabs.AcsCluster) error {
// SetAcsClusterDefaults for an AcsCluster, returns true if certs are generated
func SetAcsClusterDefaults(a *vlabs.AcsCluster) (bool, error) {
if len(a.OrchestratorProfile.ClusterID) == 0 {
a.OrchestratorProfile.ClusterID = generateClusterID(a)
}
setMasterNetworkDefaults(a)
setAgentNetworkDefaults(a)
if e := setDefaultCerts(&a.OrchestratorProfile, &a.MasterProfile); e != nil {
return e
certsGenerated, e := setDefaultCerts(&a.OrchestratorProfile, &a.MasterProfile)
if e != nil {
return false, e
}
return nil
return certsGenerated, nil
}
// generateClusterID creates a unique 8 string cluster ID
func generateClusterID(acsCluster *vlabs.AcsCluster) string {
uniqueNameSuffixSize := 8
// the name suffix uniquely identifies the cluster and is generated off a hash
// from the master dns name
h := fnv.New64a()
h.Write([]byte(acsCluster.MasterProfile.DNSPrefix))
rand.Seed(int64(h.Sum64()))
return fmt.Sprintf("%08d", rand.Uint32())[:uniqueNameSuffixSize]
}
// SetMasterNetworkDefaults for masters
@ -53,37 +71,41 @@ func setAgentNetworkDefaults(a *vlabs.AcsCluster) {
}
}
func setDefaultCerts(o *vlabs.OrchestratorProfile, m *vlabs.MasterProfile) error {
func setDefaultCerts(o *vlabs.OrchestratorProfile, m *vlabs.MasterProfile) (bool, error) {
certsGenerated := false
// auto generate certs if none of them have been set by customer
if len(o.ApiServerCertificate) == 0 && len(o.ApiServerPrivateKey) == 0 &&
len(o.CaCertificate) == 0 &&
len(o.ClientCertificate) == 0 && len(o.ClientPrivateKey) == 0 {
masterWildCardFQDN := FormatAzureProdFQDN(m.DNSPrefix, "*")
masterExtraFQDNs := FormatAzureProdFQDNs(m.DNSPrefix)
firstMasterIP := net.ParseIP(m.FirstConsecutiveStaticIP)
if firstMasterIP == nil {
return fmt.Errorf("MasterProfile.FirstConsecutiveStaticIP '%s' is an invalid IP address", m.FirstConsecutiveStaticIP)
}
ips := []net.IP{firstMasterIP}
for i := 1; i < m.Count; i++ {
ips = append(ips, net.IP{firstMasterIP[12], firstMasterIP[13], firstMasterIP[14], firstMasterIP[15] + byte(i)})
}
caPair, apiServerPair, clientPair, err := util.CreatePki(masterWildCardFQDN, masterExtraFQDNs, ips, DefaultKubernetesClusterDomain)
if err != nil {
return err
}
o.ApiServerCertificate = base64.URLEncoding.EncodeToString([]byte(apiServerPair.CertificatePem))
o.ApiServerPrivateKey = base64.URLEncoding.EncodeToString([]byte(apiServerPair.PrivateKeyPem))
o.CaCertificate = base64.URLEncoding.EncodeToString([]byte(caPair.CertificatePem))
o.SetCAPrivateKey(base64.URLEncoding.EncodeToString([]byte(caPair.PrivateKeyPem)))
o.ClientCertificate = base64.URLEncoding.EncodeToString([]byte(clientPair.CertificatePem))
o.ClientPrivateKey = base64.URLEncoding.EncodeToString([]byte(clientPair.PrivateKeyPem))
if len(o.ApiServerCertificate) > 0 || len(o.ApiServerPrivateKey) > 0 ||
len(o.CaCertificate) > 0 ||
len(o.ClientCertificate) > 0 || len(o.ClientPrivateKey) > 0 {
return certsGenerated, nil
}
return nil
masterWildCardFQDN := FormatAzureProdFQDN(m.DNSPrefix, "*")
masterExtraFQDNs := FormatAzureProdFQDNs(m.DNSPrefix)
firstMasterIP := net.ParseIP(m.FirstConsecutiveStaticIP)
if firstMasterIP == nil {
return false, fmt.Errorf("MasterProfile.FirstConsecutiveStaticIP '%s' is an invalid IP address", m.FirstConsecutiveStaticIP)
}
ips := []net.IP{firstMasterIP}
for i := 1; i < m.Count; i++ {
ips = append(ips, net.IP{firstMasterIP[12], firstMasterIP[13], firstMasterIP[14], firstMasterIP[15] + byte(i)})
}
caPair, apiServerPair, clientPair, err := util.CreatePki(masterWildCardFQDN, masterExtraFQDNs, ips, DefaultKubernetesClusterDomain)
if err != nil {
return false, err
}
certsGenerated = true
o.ApiServerCertificate = apiServerPair.CertificatePem
o.ApiServerPrivateKey = apiServerPair.PrivateKeyPem
o.CaCertificate = caPair.CertificatePem
o.SetCAPrivateKey(caPair.PrivateKeyPem)
o.ClientCertificate = clientPair.CertificatePem
o.ClientPrivateKey = clientPair.PrivateKeyPem
return certsGenerated, nil
}

Просмотреть файл

@ -2,11 +2,10 @@ package templategenerator
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"hash/fnv"
"io/ioutil"
"math/rand"
"os"
"path"
"regexp"
@ -18,6 +17,7 @@ import (
const (
kubernetesMasterCustomDataYaml = "kubernetesmastercustomdata.yml"
kubernetesAgentCustomDataYaml = "kubernetesagentcustomdata.yml"
kubeConfigJSON = "kubeconfig.json"
)
@ -73,7 +73,46 @@ func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (stri
var err error
var templ *template.Template
templateMap := template.FuncMap{
templ = template.New("acs template").Funcs(getTemplateFuncMap(acsCluster, partsDirectory))
var files []string
var baseFile string
if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS184 ||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS ||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS173 {
files = append(commonTemplateFiles, dcosTemplateFiles...)
baseFile = dcosBaseFile
} else if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Swarm {
files = append(commonTemplateFiles, swarmTemplateFiles...)
baseFile = swarmBaseFile
} else if acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes {
files = append(commonTemplateFiles, kubernetesTemplateFiles...)
baseFile = kubernetesBaseFile
} else {
return "", fmt.Errorf("orchestrator '%s' is unsupported", acsCluster.OrchestratorProfile.OrchestratorType)
}
for _, file := range files {
templateFile := path.Join(partsDirectory, file)
bytes, e := ioutil.ReadFile(templateFile)
if e != nil {
return "", fmt.Errorf("Error reading file %s: %s", templateFile, e.Error())
}
if _, err = templ.New(file).Parse(string(bytes)); err != nil {
return "", err
}
}
var b bytes.Buffer
if err = templ.ExecuteTemplate(&b, baseFile, acsCluster); err != nil {
return "", err
}
return b.String(), nil
}
// getTemplateFuncMap returns all functions used in template generation
func getTemplateFuncMap(acsCluster *vlabs.AcsCluster, partsDirectory string) map[string]interface{} {
return template.FuncMap{
"IsDCOS173": func() bool {
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS173
},
@ -112,7 +151,7 @@ func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (stri
return acsCluster.LinuxProfile.SSH.PublicKeys[0].KeyData
},
"GetUniqueNameSuffix": func() string {
return generateUniqueNameSuffix(acsCluster)
return acsCluster.OrchestratorProfile.ClusterID
},
"GetVNETAddressPrefixes": func() string {
return getVNETAddressPrefixes(acsCluster)
@ -132,6 +171,9 @@ func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (stri
"GetSizeMap": func() string {
return GetSizeMap()
},
"Base64": func(s string) string {
return base64.URLEncoding.EncodeToString([]byte(s))
},
"GetKubernetesMasterCustomData": func() string {
str, e := getSingleLineForTemplate(kubernetesMasterCustomDataYaml, partsDirectory)
if e != nil {
@ -139,6 +181,13 @@ func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (stri
}
return fmt.Sprintf("\"customData\": \"[base64(concat('%s'))]\",", str)
},
"GetKubernetesAgentCustomData": func() string {
str, e := getSingleLineForTemplate(kubernetesAgentCustomDataYaml, partsDirectory)
if e != nil {
return ""
}
return fmt.Sprintf("\"customData\": \"[base64(concat('%s'))]\",", str)
},
"GetKubernetesKubeConfig": func() string {
str, e := getSingleLineForTemplate(kubeConfigJSON, partsDirectory)
if e != nil {
@ -162,49 +211,6 @@ func GenerateTemplate(acsCluster *vlabs.AcsCluster, partsDirectory string) (stri
return dict, nil
},
}
templ = template.New("acs template").Funcs(templateMap)
var files []string
var baseFile string
if isDCOS(acsCluster) {
files = append(commonTemplateFiles, dcosTemplateFiles...)
baseFile = dcosBaseFile
} else if isSwarm(acsCluster) {
files = append(commonTemplateFiles, swarmTemplateFiles...)
baseFile = swarmBaseFile
} else if isKubernetes(acsCluster) {
files = append(commonTemplateFiles, kubernetesTemplateFiles...)
baseFile = kubernetesBaseFile
} else {
return "", fmt.Errorf("orchestrator '%s' is unsupported", acsCluster.OrchestratorProfile.OrchestratorType)
}
for _, file := range files {
templateFile := path.Join(partsDirectory, file)
bytes, e := ioutil.ReadFile(templateFile)
if e != nil {
return "", fmt.Errorf("Error reading file %s: %s", templateFile, e.Error())
}
if _, err = templ.New(file).Parse(string(bytes)); err != nil {
return "", err
}
}
var b bytes.Buffer
if err = templ.ExecuteTemplate(&b, baseFile, acsCluster); err != nil {
return "", err
}
return b.String(), nil
}
func generateUniqueNameSuffix(acsCluster *vlabs.AcsCluster) string {
uniqueNameSuffixSize := 8
// the name suffix uniquely identifies the cluster and is generated off a hash
// from the master dns name
h := fnv.New64a()
h.Write([]byte(acsCluster.MasterProfile.DNSPrefix))
rand.Seed(int64(h.Sum64()))
return fmt.Sprintf("%08d", rand.Uint32())[:uniqueNameSuffixSize]
}
func getPackageGUID(orchestratorType string, masterCount int) string {
@ -431,20 +437,6 @@ func getAgentRolesFileContents(ports []int) string {
return `{\"content\": \"\", \"path\": \"/etc/mesosphere/roles/slave\"},`
}
func isDCOS(acsCluster *vlabs.AcsCluster) bool {
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS184 ||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS ||
acsCluster.OrchestratorProfile.OrchestratorType == vlabs.DCOS173
}
func isSwarm(acsCluster *vlabs.AcsCluster) bool {
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Swarm
}
func isKubernetes(acsCluster *vlabs.AcsCluster) bool {
return acsCluster.OrchestratorProfile.OrchestratorType == vlabs.Kubernetes
}
// getSingleLineForTemplate returns the file as a single line for embedding in an arm template
func getSingleLineForTemplate(yamlFilename string, partsDirectory string) (string, error) {
yamlFile := path.Join(partsDirectory, yamlFilename)