зеркало из https://github.com/Azure/aks-engine.git
1. complete agent defintions
2. write out cert files
This commit is contained in:
Родитель
cf14d79db0
Коммит
1a9333629f
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче