func FromYaml(c []byte) (types.Resource, error) {
	return types.ResourceFromYaml(c, &Controlplane{})
}
FromYaml allows to restore controlplane configuration and state from YAML format.
package controlplane
import (
	"fmt"
	"sigs.k8s.io/yaml"
	"github.com/flexkube/libflexkube/internal/util"
	"github.com/flexkube/libflexkube/pkg/container"
	"github.com/flexkube/libflexkube/pkg/defaults"
	"github.com/flexkube/libflexkube/pkg/host"
	"github.com/flexkube/libflexkube/pkg/host/transport/ssh"
	"github.com/flexkube/libflexkube/pkg/kubernetes/client"
	"github.com/flexkube/libflexkube/pkg/pki"
	"github.com/flexkube/libflexkube/pkg/types"
)
type Common struct {
	Image string `json:"image,omitempty"`
	KubernetesCACertificate types.Certificate `json:"kubernetesCACertificate,omitempty"`
	FrontProxyCACertificate types.Certificate `json:"frontProxyCACertificate,omitempty"`
}
type Controlplane struct {
	Common *Common `json:"common,omitempty"`
	SSH *ssh.Config `json:"ssh,omitempty"`
	APIServerAddress string `json:"apiServerAddress,omitempty"`
	APIServerPort int `json:"apiServerPort,omitempty"`
	KubeAPIServer KubeAPIServer `json:"kubeAPIServer,omitempty"`
	KubeControllerManager KubeControllerManager `json:"kubeControllerManager,omitempty"`
	KubeScheduler KubeScheduler `json:"kubeScheduler,omitempty"`
	Destroy bool `json:"destroy,omitempty"`
	PKI *pki.PKI `json:"pki,omitempty"`
	State *container.ContainersState `json:"state,omitempty"`
}
type controlplane struct {
	containers container.ContainersInterface
}
func (c *Controlplane) propagateKubeconfig(d *client.Config) {
	pkiCA := types.Certificate("")
	if c.PKI != nil && c.PKI.Kubernetes != nil && c.PKI.Kubernetes.CA != nil {
		pkiCA = c.PKI.Kubernetes.CA.X509Certificate
	}
	d.CACertificate = d.CACertificate.Pick(c.Common.KubernetesCACertificate, pkiCA)
	if c.APIServerAddress != "" && c.APIServerPort != 0 {
		d.Server = util.PickString(d.Server, fmt.Sprintf("%s:%d", c.APIServerAddress, c.APIServerPort))
	}
}
func (c *Controlplane) propagateHost(h *host.Host) *host.Host {
	if h == nil {
		h = &host.Host{}
	}
	nh := host.BuildConfig(*h, host.Host{
		SSHConfig: c.SSH,
	})
	return &nh
}
func (c *Controlplane) propagateCommon(co *Common) {
	if co == nil {
		co = &Common{}
	}
	if c.Common == nil {
		c.Common = &Common{}
	}
	co.Image = util.PickString(co.Image, c.Common.Image)
	var pkiCA types.Certificate
	if c.PKI != nil && c.PKI.Kubernetes != nil && c.PKI.Kubernetes.CA != nil {
		pkiCA = c.PKI.Kubernetes.CA.X509Certificate
	}
	var frontProxyCA types.Certificate
	if c.PKI != nil && c.PKI.Kubernetes != nil && c.PKI.Kubernetes.FrontProxyCA != nil {
		frontProxyCA = c.PKI.Kubernetes.FrontProxyCA.X509Certificate
	}
	co.KubernetesCACertificate = co.KubernetesCACertificate.Pick(c.Common.KubernetesCACertificate, pkiCA)
	co.FrontProxyCACertificate = co.FrontProxyCACertificate.Pick(c.Common.FrontProxyCACertificate, frontProxyCA)
}
func (c *Controlplane) buildKubeScheduler() {
	k := &c.KubeScheduler
	c.propagateKubeconfig(&k.Kubeconfig)
	c.propagateCommon(k.Common)
	if c.PKI != nil && c.PKI.Kubernetes != nil && c.PKI.Kubernetes.KubeSchedulerCertificate != nil {
		k.Kubeconfig.ClientCertificate = k.Kubeconfig.ClientCertificate.Pick(
			c.PKI.Kubernetes.KubeSchedulerCertificate.X509Certificate)
		k.Kubeconfig.ClientKey = k.Kubeconfig.ClientKey.Pick(c.PKI.Kubernetes.KubeSchedulerCertificate.PrivateKey)
	}
	k.Host = c.propagateHost(k.Host)
}
func (c *Controlplane) buildKubeControllerManager() {
	k := &c.KubeControllerManager
	c.propagateKubeconfig(&k.Kubeconfig)
	c.propagateCommon(k.Common)
	if c.PKI != nil && c.PKI.Kubernetes != nil {
		if c.PKI.Kubernetes.KubeControllerManagerCertificate != nil {
			k.Kubeconfig.ClientCertificate = k.Kubeconfig.ClientCertificate.Pick(
				c.PKI.Kubernetes.KubeControllerManagerCertificate.X509Certificate)
			k.Kubeconfig.ClientKey = k.Kubeconfig.ClientKey.Pick(c.PKI.Kubernetes.KubeControllerManagerCertificate.PrivateKey)
		}
		if c.PKI.Kubernetes.CA != nil {
			k.KubernetesCAKey = k.KubernetesCAKey.Pick(c.PKI.Kubernetes.CA.PrivateKey)
		}
		if c.PKI.RootCA != nil {
			k.RootCACertificate = k.RootCACertificate.Pick(c.PKI.RootCA.X509Certificate)
		}
		if c.PKI.Kubernetes.ServiceAccountCertificate != nil {
			k.ServiceAccountPrivateKey = k.ServiceAccountPrivateKey.Pick(c.PKI.Kubernetes.ServiceAccountCertificate.PrivateKey)
		}
	}
	k.Host = c.propagateHost(k.Host)
	k.FlexVolumePluginDir = util.PickString(k.FlexVolumePluginDir, defaults.VolumePluginDir)
}
func (c *Controlplane) kubeAPIServerPKIIntegration() {
	if c.PKI == nil {
		return
	}
	k := &c.KubeAPIServer
	if p := c.PKI.Etcd; p != nil {
		c.mergeEtcdCertificatesFromPKI(*p)
	}
	if c.PKI.Kubernetes == nil {
		return
	}
	if p := c.PKI.Kubernetes.ServiceAccountCertificate; p != nil {
		k.ServiceAccountPrivateKey = util.PickString(k.ServiceAccountPrivateKey, string(p.PrivateKey))
	}
	p := c.PKI.Kubernetes.KubeAPIServer
	if p == nil {
		return
	}
	c.mergeKubeAPIServerCertificatesFromPKI(*p)
}
func (c *Controlplane) mergeEtcdCertificatesFromPKI(p pki.Etcd) {
	if c.PKI == nil {
		return
	}
	k := &c.KubeAPIServer
	if p.CA != nil {
		k.EtcdCACertificate = k.EtcdCACertificate.Pick(p.CA.X509Certificate)
	}
	for _, cn := range []string{"root", "kube-apiserver"} {
		if c, ok := p.ClientCertificates[cn]; ok {
			k.EtcdClientCertificate = k.EtcdClientCertificate.Pick(c.X509Certificate)
			k.EtcdClientKey = k.EtcdClientKey.Pick(c.PrivateKey)
		}
	}
}
func (c *Controlplane) mergeKubeAPIServerCertificatesFromPKI(p pki.KubeAPIServer) {
	k := &c.KubeAPIServer
	if c := p.ServerCertificate; c != nil {
		k.APIServerCertificate = k.APIServerCertificate.Pick(c.X509Certificate)
		k.APIServerKey = k.APIServerKey.Pick(c.PrivateKey)
	}
	if c := p.FrontProxyClientCertificate; c != nil {
		k.FrontProxyCertificate = k.FrontProxyCertificate.Pick(c.X509Certificate)
		k.FrontProxyKey = k.FrontProxyKey.Pick(c.PrivateKey)
	}
	if c := p.KubeletCertificate; c != nil {
		k.KubeletClientCertificate = k.KubeletClientCertificate.Pick(c.X509Certificate)
		k.KubeletClientKey = k.KubeletClientKey.Pick(c.PrivateKey)
	}
}
func (c *Controlplane) buildKubeAPIServer() {
	k := &c.KubeAPIServer
	if k.BindAddress == "" && c.APIServerAddress != "" {
		k.BindAddress = c.APIServerAddress
	}
	if k.AdvertiseAddress == "" && c.APIServerAddress != "" {
		k.AdvertiseAddress = c.APIServerAddress
	}
	if k.SecurePort == 0 && c.APIServerPort != 0 {
		k.SecurePort = c.APIServerPort
	}
	c.propagateCommon(k.Common)
	c.kubeAPIServerPKIIntegration()
	k.Host = c.propagateHost(k.Host)
}
func (c *Controlplane) New() (types.Resource, error) {
	if err := c.Validate(); err != nil {
		return nil, fmt.Errorf("validating controlplane configuration: %w", err)
	}
	controlplane, cc, _ := c.containersWithState()  
	if c.Destroy {
		return controlplane, nil
	}
	c.buildComponents()
	kas, _ := c.KubeAPIServer.New()               
	kasHcc, _ := kas.ToHostConfiguredContainer()  
	kcm, _ := c.KubeControllerManager.New()       
	kcmHcc, _ := kcm.ToHostConfiguredContainer()  
	ks, _ := c.KubeScheduler.New()              
	ksHcc, _ := ks.ToHostConfiguredContainer()  
	cc.DesiredState = container.ContainersState{
		"kube-apiserver":          kasHcc,
		"kube-controller-manager": kcmHcc,
		"kube-scheduler":          ksHcc,
	}
	co, _ := cc.New()  
	controlplane.containers = co
	return controlplane, nil
}
func (c *Controlplane) buildComponents() {
	c.buildKubeAPIServer()
	c.buildKubeControllerManager()
	c.buildKubeScheduler()
}
func (c *Controlplane) containersWithState() (*controlplane, *container.Containers, error) {
	cp := &controlplane{}
	cc := &container.Containers{}
	if c.State == nil || len(*c.State) == 0 {
		return cp, cc, nil
	}
	cc.PreviousState = *c.State
	ci, err := cc.New()
	if err != nil {
		return nil, nil, fmt.Errorf("creating containers state: %w", err)
	}
	cp.containers = ci
	return cp, cc, nil
}
type controlplaneComponentConfiguration interface {
	New() (container.ResourceInstance, error)
}
func validateControlplaneComponent(
	ccc controlplaneComponentConfiguration,
	name string,
) (*container.HostConfiguredContainer, error) {
	cc, err := ccc.New()
	if err != nil {
		return nil, fmt.Errorf("verifying %q configuration: %w", name, err)
	}
	hcc, err := cc.ToHostConfiguredContainer()
	if err != nil {
		return nil, fmt.Errorf("building %q container configuration: %w", name, err)
	}
	return hcc, nil
}
func (c *Controlplane) Validate() error {
	c.buildComponents()
	var errors util.ValidateErrors
	if c.Destroy && (c.State == nil || len(*c.State) == 0) {
		errors = append(errors, fmt.Errorf("can't destroy non-existent controlplane"))
	}
	_, cc, err := c.containersWithState()
	if err != nil {
		errors = append(errors, fmt.Errorf("malformed containers state: %w", err))
	}
	if c.Destroy {
		return errors.Return()
	}
	containersState, controlplaneComponentsErrors := c.controlplaneComponentsToContainersState()
	errors = append(errors, controlplaneComponentsErrors...)
	if len(errors) > 0 {
		return errors.Return()
	}
	cc.DesiredState = containersState
	if _, err = cc.New(); err != nil {
		errors = append(errors, fmt.Errorf("generating containers configuration: %w", err))
	}
	return errors.Return()
}
func (c *Controlplane) controlplaneComponentsToContainersState() (container.ContainersState, util.ValidateErrors) {
	var errors util.ValidateErrors
	kasHcc, err := validateControlplaneComponent(&c.KubeAPIServer, "kube-apiserver")
	if err != nil {
		errors = append(errors, fmt.Errorf("validating kube-apiserver configuration: %w", err))
	}
	kcmHcc, err := validateControlplaneComponent(&c.KubeControllerManager, "kube-controller-manager")
	if err != nil {
		errors = append(errors, fmt.Errorf("validating kube-controller-manager: %w", err))
	}
	ksHcc, err := validateControlplaneComponent(&c.KubeScheduler, "kube-scheduler")
	if err != nil {
		errors = append(errors, fmt.Errorf("validating kube-scheduler configuration: %w", err))
	}
	return container.ContainersState{
		"kube-apiserver":          kasHcc,
		"kube-controller-manager": kcmHcc,
		"kube-scheduler":          ksHcc,
	}, errors
}