feat: konnectivity

This commit is contained in:
mendrugory
2022-05-26 13:06:46 +02:00
committed by Gonzalo Gabriel Jiménez Fuentes
parent 5b4de76229
commit 3be6cf1c4f
30 changed files with 1875 additions and 1176 deletions

View File

@@ -42,3 +42,32 @@ func (in *TenantControlPlane) GetControlPlaneAddress(ctx context.Context, client
return "", kamajierrors.MissingValidIPError{}
}
func (in *TenantControlPlane) GetKonnectivityServerAddress(ctx context.Context, client client.Client) (string, error) {
var loadBalancerStatus corev1.LoadBalancerStatus
svc := &corev1.Service{}
err := client.Get(ctx, types.NamespacedName{Namespace: in.GetNamespace(), Name: in.Status.Addons.Konnectivity.Service.Name}, svc)
if err != nil {
return "", errors.Wrap(err, "cannot retrieve Service for Konnectivity")
}
switch {
case len(in.Spec.Addons.Konnectivity.ProxyHost) > 0:
// Returning the hard-coded value in the specification in case of non LoadBalanced resources
return in.Spec.Addons.Konnectivity.ProxyHost, nil
case svc.Spec.Type == corev1.ServiceTypeLoadBalancer:
loadBalancerStatus = svc.Status.LoadBalancer
if len(loadBalancerStatus.Ingress) == 0 {
return "", kamajierrors.NonExposedLoadBalancerError{}
}
for _, lb := range loadBalancerStatus.Ingress {
if ip := lb.IP; len(ip) > 0 {
return ip, nil
}
}
}
return "", kamajierrors.MissingValidIPError{}
}

View File

@@ -98,13 +98,14 @@ type AddonSpec struct{}
// KonnectivitySpec defines the spec for Konnectivity.
type KonnectivitySpec struct {
// Port of Konnectivity proxy server.
// +kubebuilder:default=8132
ProxyPort int32 `json:"proxyPort"`
// Host of Konnectivity proxy server.
ProxyHost string `json:"proxyHost,omitempty"`
AllowAddressAsExternalIP bool `json:"allowAddressAsExternalIP,omitempty"`
// ServiceType allows specifying how to expose the Konnectivity Proxy Server.
ServiceType ServiceType `json:"serviceType"`
// Version for Konnectivity server and agent.
// +kubebuilder:default=v0.0.16
// +kubebuilder:default=v0.0.31
Version string `json:"version,omitempty"`
// ServerImage defines the container image for Konnectivity's server.
// +kubebuilder:default=us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-server
@@ -155,8 +156,9 @@ type ETCDCertificatesStatus struct {
// CertificatePrivateKeyPair defines the status.
type CertificatePrivateKeyPairStatus struct {
SecretName string `json:"secretName,omitempty"`
LastUpdate metav1.Time `json:"lastUpdate,omitempty"`
SecretName string `json:"secretName,omitempty"`
LastUpdate metav1.Time `json:"lastUpdate,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
}
// CertificatePrivateKeyPair defines the status.
@@ -228,6 +230,27 @@ type KubeadmPhasesStatus struct {
BootstrapToken KubeadmPhaseStatus `json:"bootstrapToken"`
}
type ExternalKubernetesObjectStatus struct {
Name string `json:"name,omitempty"`
Namespace string `json:"namespace,omitempty"`
// Resource version of k8s object
RV string `json:"resourceVersion,omitempty"`
// Last time when k8s object was updated
LastUpdate metav1.Time `json:"lastUpdate,omitempty"`
}
// KonnectivityStatus defines the status of Konnectivity as Addon.
type KonnectivityStatus struct {
Enabled bool `json:"enabled"`
EgressSelectorConfiguration string `json:"egressSelectorConfiguration,omitempty"`
Certificate CertificatePrivateKeyPairStatus `json:"certificate,omitempty"`
Kubeconfig KubeconfigStatus `json:"kubeconfig,omitempty"`
ServiceAccount ExternalKubernetesObjectStatus `json:"sa,omitempty"`
ClusterRoleBinding ExternalKubernetesObjectStatus `json:"clusterrolebinding,omitempty"`
Agent ExternalKubernetesObjectStatus `json:"agent,omitempty"`
Service KubernetesServiceStatus `json:"service,omitempty"`
}
// AddonStatus defines the observed state of an Addon.
type AddonStatus struct {
Enabled bool `json:"enabled"`
@@ -247,6 +270,8 @@ func (d *AddonStatus) SetKubeadmConfigResourceVersion(rv string) {
type AddonsStatus struct {
CoreDNS AddonStatus `json:"coreDNS,omitempty"`
KubeProxy AddonStatus `json:"kubeProxy,omitempty"`
Konnectivity KonnectivityStatus `json:"konnectivity,omitempty"`
}
// TenantControlPlaneStatus defines the observed state of TenantControlPlane.
@@ -305,6 +330,8 @@ type KubernetesDeploymentStatus struct {
Name string `json:"name"`
// The namespace which the Deployment for the given cluster is deployed.
Namespace string `json:"namespace"`
// Last time when deployment was updated
LastUpdate metav1.Time `json:"lastUpdate,omitempty"`
}
// KubernetesServiceStatus defines the status for the Tenant Control Plane Service in the management cluster.

View File

@@ -123,6 +123,7 @@ func (in *AddonsStatus) DeepCopyInto(out *AddonsStatus) {
*out = *in
in.CoreDNS.DeepCopyInto(&out.CoreDNS)
in.KubeProxy.DeepCopyInto(&out.KubeProxy)
in.Konnectivity.DeepCopyInto(&out.Konnectivity)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddonsStatus.
@@ -280,6 +281,22 @@ func (in *ETCDStatus) DeepCopy() *ETCDStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExternalKubernetesObjectStatus) DeepCopyInto(out *ExternalKubernetesObjectStatus) {
*out = *in
in.LastUpdate.DeepCopyInto(&out.LastUpdate)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalKubernetesObjectStatus.
func (in *ExternalKubernetesObjectStatus) DeepCopy() *ExternalKubernetesObjectStatus {
if in == nil {
return nil
}
out := new(ExternalKubernetesObjectStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IngressSpec) DeepCopyInto(out *IngressSpec) {
*out = *in
@@ -435,6 +452,7 @@ func (in *KubeletSpec) DeepCopy() *KubeletSpec {
func (in *KubernetesDeploymentStatus) DeepCopyInto(out *KubernetesDeploymentStatus) {
*out = *in
in.DeploymentStatus.DeepCopyInto(&out.DeploymentStatus)
in.LastUpdate.DeepCopyInto(&out.LastUpdate)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesDeploymentStatus.

View File

@@ -80,7 +80,6 @@ spec:
description: Host of Konnectivity proxy server.
type: string
proxyPort:
default: 8132
description: Port of Konnectivity proxy server.
format: int32
type: integer
@@ -89,12 +88,21 @@ spec:
description: ServerImage defines the container image for Konnectivity's
server.
type: string
serviceType:
description: ServiceType allows specifying how to expose the
Konnectivity Proxy Server.
enum:
- ClusterIP
- NodePort
- LoadBalancer
type: string
version:
default: v0.0.16
default: v0.0.31
description: Version for Konnectivity server and agent.
type: string
required:
- proxyPort
- serviceType
type: object
kubeProxy:
description: AddonSpec defines the spec for every addon.
@@ -334,6 +342,248 @@ spec:
required:
- enabled
type: object
konnectivity:
description: KonnectivityStatus defines the status of Konnectivity
as Addon.
properties:
agent:
properties:
lastUpdate:
description: Last time when k8s object was updated
format: date-time
type: string
name:
type: string
namespace:
type: string
resourceVersion:
description: Resource version of k8s object
type: string
type: object
certificate:
description: CertificatePrivateKeyPair defines the status.
properties:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
clusterrolebinding:
properties:
lastUpdate:
description: Last time when k8s object was updated
format: date-time
type: string
name:
type: string
namespace:
type: string
resourceVersion:
description: Resource version of k8s object
type: string
type: object
egressSelectorConfiguration:
type: string
enabled:
type: boolean
kubeconfig:
description: TenantControlPlaneKubeconfigsStatus contains
information about a the generated kubeconfig.
properties:
lastUpdate:
format: date-time
type: string
secretName:
type: string
type: object
sa:
properties:
lastUpdate:
description: Last time when k8s object was updated
format: date-time
type: string
name:
type: string
namespace:
type: string
resourceVersion:
description: Resource version of k8s object
type: string
type: object
service:
description: KubernetesServiceStatus defines the status for
the Tenant Control Plane Service in the management cluster.
properties:
conditions:
description: Current service state
items:
description: "Condition contains details for one aspect
of the current state of this API Resource. --- This
struct is intended for direct use as an array at the
field path .status.conditions. For example, type
FooStatus struct{ // Represents the observations
of a foo's current state. // Known .status.conditions.type
are: \"Available\", \"Progressing\", and \"Degraded\"
\ // +patchMergeKey=type // +patchStrategy=merge
\ // +listType=map // +listMapKey=type Conditions
[]metav1.Condition `json:\"conditions,omitempty\"
patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
\n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time
the condition transitioned from one status to
another. This should be when the underlying condition
changed. If that is not known, then using the
time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message
indicating details about the transition. This
may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance,
if .metadata.generation is currently 12, but the
.status.conditions[x].observedGeneration is 9,
the condition is out of date with respect to the
current state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier
indicating the reason for the condition's last
transition. Producers of specific condition types
may define expected values and meanings for this
field, and whether the values are considered a
guaranteed API. The value should be a CamelCase
string. This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True,
False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in
foo.example.com/CamelCase. --- Many .condition.type
values are consistent across resources like Available,
but because arbitrary conditions can be useful
(see .node.status.conditions), the ability to
deconflict is important. The regex it matches
is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
loadBalancer:
description: LoadBalancer contains the current status
of the load-balancer, if one is present.
properties:
ingress:
description: Ingress is a list containing ingress
points for the load-balancer. Traffic intended for
the service should be sent to these ingress points.
items:
description: 'LoadBalancerIngress represents the
status of a load-balancer ingress point: traffic
intended for the service should be sent to an
ingress point.'
properties:
hostname:
description: Hostname is set for load-balancer
ingress points that are DNS based (typically
AWS load-balancers)
type: string
ip:
description: IP is set for load-balancer ingress
points that are IP based (typically GCE or
OpenStack load-balancers)
type: string
ports:
description: Ports is a list of records of service
ports If used, every port defined in the service
should have an entry in it
items:
properties:
error:
description: 'Error is to record the problem
with the service port The format of
the error shall comply with the following
rules: - built-in error values shall
be specified in this file and those
shall use CamelCase names - cloud
provider specific error values must
have names that comply with the format
foo.example.com/CamelCase. --- The regex
it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)'
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
port:
description: Port is the port number of
the service port of which status is
recorded here
format: int32
type: integer
protocol:
default: TCP
description: 'Protocol is the protocol
of the service port of which status
is recorded here The supported values
are: "TCP", "UDP", "SCTP"'
type: string
required:
- port
- protocol
type: object
type: array
x-kubernetes-list-type: atomic
type: object
type: array
type: object
name:
description: The name of the Service for the given cluster.
type: string
namespace:
description: The namespace which the Service for the given
cluster is deployed.
type: string
port:
description: The port where the service is running
format: int32
type: integer
required:
- name
- namespace
- port
type: object
required:
- enabled
type: object
kubeProxy:
description: AddonStatus defines the observed state of an Addon.
properties:
@@ -358,6 +608,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -367,6 +619,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -376,6 +630,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -410,6 +666,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -419,6 +677,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -579,6 +839,10 @@ spec:
- type
type: object
type: array
lastUpdate:
description: Last time when deployment was updated
format: date-time
type: string
name:
description: The name of the Deployment for the given cluster.
type: string

View File

@@ -61,39 +61,48 @@ spec:
description: TenantControlPlaneSpec defines the desired state of TenantControlPlane.
properties:
addons:
default:
coreDNS:
enabled: true
kubeProxy:
enabled: true
description: Addons contain which addons are enabled
properties:
coreDNS:
default:
enabled: true
description: AddonSpec defines the spec for every addon.
properties:
enabled:
default: true
type: boolean
type: object
konnectivity:
default:
enabled: true
description: AddonSpec defines the spec for every addon.
description: KonnectivitySpec defines the spec for Konnectivity.
properties:
enabled:
default: true
agentImage:
default: us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-agent
description: AgentImage defines the container image for Konnectivity's agent.
type: string
allowAddressAsExternalIP:
type: boolean
proxyHost:
description: Host of Konnectivity proxy server.
type: string
proxyPort:
description: Port of Konnectivity proxy server.
format: int32
type: integer
serverImage:
default: us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-server
description: ServerImage defines the container image for Konnectivity's server.
type: string
serviceType:
description: ServiceType allows specifying how to expose the Konnectivity Proxy Server.
enum:
- ClusterIP
- NodePort
- LoadBalancer
type: string
version:
default: v0.0.31
description: Version for Konnectivity server and agent.
type: string
required:
- proxyPort
- serviceType
type: object
kubeProxy:
default:
enabled: true
description: AddonSpec defines the spec for every addon.
properties:
enabled:
default: true
type: boolean
type: object
type: object
controlPlane:
@@ -310,10 +319,181 @@ spec:
- enabled
type: object
konnectivity:
description: KonnectivityStatus defines the status of Konnectivity as Addon
description: KonnectivityStatus defines the status of Konnectivity as Addon.
properties:
egressSelectorConfigurationStatus:
agent:
properties:
lastUpdate:
description: Last time when k8s object was updated
format: date-time
type: string
name:
type: string
namespace:
type: string
resourceVersion:
description: Resource version of k8s object
type: string
type: object
certificate:
description: CertificatePrivateKeyPair defines the status.
properties:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
clusterrolebinding:
properties:
lastUpdate:
description: Last time when k8s object was updated
format: date-time
type: string
name:
type: string
namespace:
type: string
resourceVersion:
description: Resource version of k8s object
type: string
type: object
egressSelectorConfiguration:
type: string
enabled:
type: boolean
kubeconfig:
description: TenantControlPlaneKubeconfigsStatus contains information about a the generated kubeconfig.
properties:
lastUpdate:
format: date-time
type: string
secretName:
type: string
type: object
sa:
properties:
lastUpdate:
description: Last time when k8s object was updated
format: date-time
type: string
name:
type: string
namespace:
type: string
resourceVersion:
description: Resource version of k8s object
type: string
type: object
service:
description: KubernetesServiceStatus defines the status for the Tenant Control Plane Service in the management cluster.
properties:
conditions:
description: Current service state
items:
description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
loadBalancer:
description: LoadBalancer contains the current status of the load-balancer, if one is present.
properties:
ingress:
description: Ingress is a list containing ingress points for the load-balancer. Traffic intended for the service should be sent to these ingress points.
items:
description: 'LoadBalancerIngress represents the status of a load-balancer ingress point: traffic intended for the service should be sent to an ingress point.'
properties:
hostname:
description: Hostname is set for load-balancer ingress points that are DNS based (typically AWS load-balancers)
type: string
ip:
description: IP is set for load-balancer ingress points that are IP based (typically GCE or OpenStack load-balancers)
type: string
ports:
description: Ports is a list of records of service ports If used, every port defined in the service should have an entry in it
items:
properties:
error:
description: 'Error is to record the problem with the service port The format of the error shall comply with the following rules: - built-in error values shall be specified in this file and those shall use CamelCase names - cloud provider specific error values must have names that comply with the format foo.example.com/CamelCase. --- The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)'
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
port:
description: Port is the port number of the service port of which status is recorded here
format: int32
type: integer
protocol:
default: TCP
description: 'Protocol is the protocol of the service port of which status is recorded here The supported values are: "TCP", "UDP", "SCTP"'
type: string
required:
- port
- protocol
type: object
type: array
x-kubernetes-list-type: atomic
type: object
type: array
type: object
name:
description: The name of the Service for the given cluster.
type: string
namespace:
description: The namespace which the Service for the given cluster is deployed.
type: string
port:
description: The port where the service is running
format: int32
type: integer
required:
- name
- namespace
- port
type: object
required:
- enabled
type: object
kubeProxy:
description: AddonStatus defines the observed state of an Addon.
@@ -338,6 +518,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -347,6 +529,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -356,6 +540,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -387,6 +573,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -396,6 +584,8 @@ spec:
lastUpdate:
format: date-time
type: string
resourceVersion:
type: string
secretName:
type: string
type: object
@@ -535,6 +725,10 @@ spec:
- type
type: object
type: array
lastUpdate:
description: Last time when deployment was updated
format: date-time
type: string
name:
description: The name of the Deployment for the given cluster.
type: string

View File

@@ -1,53 +0,0 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
name: tenantkind
spec:
controlPlane:
deployment:
replicas: 2
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: deployment
service:
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: service
serviceType: ClusterIP
ingress:
enabled: true
hostname: kamaji.local
ingressClassName: nginx
additionalMetadata:
annotations:
kubernetes.io/ingress.allow-http: "false"
nginx.ingress.kubernetes.io/secure-backends: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
kubernetes:
version: "v1.23.4"
kubelet:
cgroupfs: systemd
admissionControllers:
- LimitRanger
- ResourceQuota
networkProfile:
address: "172.18.0.2"
port: 6443
domain: "clastix.labs"
serviceCidr: "10.96.0.0/16"
podCidr: "10.244.0.0/16"
dnsServiceIPs:
- "10.96.0.10"
# addons:
# coreDNS:
# # enabled: true
# kubeProxy:
# # enabled: false

View File

@@ -1,48 +0,0 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
name: tenant1
spec:
controlPlane:
deployment:
replicas: 2
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: deployment
service:
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: service
serviceType: NodePort
ingress:
enabled: false
kubernetes:
version: "v1.23.4"
kubelet:
cgroupfs: cgroupfs
admissionControllers:
- LimitRanger
- ResourceQuota
networkProfile:
address: "172.18.0.2"
port: 31443
domain: "clastix.labs"
serviceCidr: "10.96.0.0/16"
podCidr: "10.244.0.0/16"
dnsServiceIPs:
- "10.96.0.10"
addons:
konnectivity:
proxyPort: 31132
proxyHost: "172.18.0.2"
version: v0.0.31
coreDNS: {}
kubeProxy:

View File

@@ -1,53 +0,0 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
name: tenantkind
spec:
controlPlane:
deployment:
replicas: 2
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: deployment
service:
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: service
serviceType: ClusterIP
ingress:
enabled: true
hostname: kamaji.local
ingressClassName: nginx
additionalMetadata:
annotations:
kubernetes.io/ingress.allow-http: "false"
nginx.ingress.kubernetes.io/secure-backends: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
kubernetes:
version: "v1.23.4"
kubelet:
cgroupfs: systemd
# admissionControllers:
# - LimitRanger
# - ResourceQuota
networkProfile:
address: "172.18.0.2"
port: 6443
domain: "clastix.labs"
serviceCidr: "10.96.0.0/16"
podCidr: "10.244.0.0/16"
dnsServiceIPs:
- "10.96.0.10"
addons:
coreDNS:
enabled: false
# kubeProxy:
# enabled: false

View File

@@ -1,40 +0,0 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
name: tenant-00
namespace: tenants
spec:
controlPlane:
deployment:
replicas: 2
additionalMetadata:
annotations:
environment.clastix.io: tenant-00
labels:
tenant.clastix.io: tenant-00
kind.clastix.io: deployment
service:
additionalMetadata:
annotations:
environment.clastix.io: tenant-00
labels:
tenant.clastix.io: tenant-00
kind.clastix.io: service
serviceType: LoadBalancer
ingress:
enabled: false
kubernetes:
version: v1.23.1
kubelet:
cgroupfs: systemd
admissionControllers:
- ResourceQuota
- LimitRanger
networkProfile:
address: 192.168.32.150
port: 6443
domain: clastix.labs
serviceCidr: 10.96.0.0/16
podCidr: 10.36.0.0/16
dnsServiceIPs:
- 10.96.0.10

View File

@@ -1,49 +0,0 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
name: test
namespace: default
spec:
controlPlane:
deployment:
replicas: 2
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: deployment
service:
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: service
serviceType: ClusterIP
ingress:
enabled: false
hostname: kamaji.local
ingressClassName: nginx
additionalMetadata:
annotations:
kubernetes.io/ingress.allow-http: "false"
nginx.ingress.kubernetes.io/secure-backends: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
kubernetes:
version: "v1.23.1"
kubelet:
cgroupfs: systemd
admissionControllers:
- ResourceQuota
- LimitRanger
networkProfile:
address: "192.168.1.47"
port: 6443
domain: "clastix.labs"
serviceCidr: "10.152.0.0/16"
podCidr: "10.1.0.0/16"
dnsServiceIPs:
- "10.152.183.10"

View File

@@ -1,41 +0,0 @@
apiVersion: kamaji.clastix.io/v1alpha1
kind: TenantControlPlane
metadata:
name: tenant1
spec:
controlPlane:
deployment:
replicas: 2
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: deployment
service:
additionalMetadata:
annotations:
environment.clastix.io: test
tier.clastix.io: "0"
labels:
tenant.clastix.io: test
kind.clastix.io: service
serviceType: NodePort
ingress:
enabled: false
kubernetes:
version: "v1.23.4"
kubelet:
cgroupfs: cgroupfs
admissionControllers:
- LimitRanger
- ResourceQuota
networkProfile:
address: "192.168.1.47"
port: 31443
domain: "clastix.labs"
serviceCidr: "10.96.0.0/16"
podCidr: "10.244.0.0/16"
dnsServiceIPs:
- "10.96.0.10"

View File

@@ -1,3 +1,5 @@
// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package controllers
import (
@@ -41,7 +43,7 @@ func GetResources(config GroupResourceBuilderConfiguration) []resources.Resource
// GetDeleteableResources returns a list of resources that have to be deleted when tenant control planes are deleted
// Currently there is only a default approach
// TODO: the idea of this function is to become a factory to return the group of deleteable resources according to the given configuration
// TODO: the idea of this function is to become a factory to return the group of deleteable resources according to the given configuration.
func GetDeleteableResources(config GroupDeleteableResourceBuilderConfiguration) []resources.DeleteableResource {
return getDefaultDeleteableResources(config)
}
@@ -52,11 +54,12 @@ func getDefaultResources(config GroupResourceBuilderConfiguration) []resources.R
resources = append(resources, getKubernetesCertificatesResources(config.client, config.log, config.tcpReconcilerConfig, config.tenantControlPlane)...)
resources = append(resources, getKubeconfigResources(config.client, config.log, config.tcpReconcilerConfig, config.tenantControlPlane)...)
resources = append(resources, getKubernetesStorageResources(config.client, config.log, config.tcpReconcilerConfig, config.tenantControlPlane)...)
resources = append(resources, getKonnectivityResources(config.client, config.tenantControlPlane)...)
resources = append(resources, getInternalKonnectivityResources(config.client, config.log, config.tcpReconcilerConfig, config.tenantControlPlane)...)
resources = append(resources, getKubernetesDeploymentResources(config.client, config.tcpReconcilerConfig, config.tenantControlPlane)...)
resources = append(resources, getKubernetesIngressResources(config.client, config.tenantControlPlane)...)
resources = append(resources, getKubeadmPhaseResources(config.client, config.log, config.tenantControlPlane)...)
resources = append(resources, getKubeadmAddonResources(config.client, config.log, config.tenantControlPlane)...)
resources = append(resources, getExternalKonnectivityResources(config.client, config.log, config.tcpReconcilerConfig, config.tenantControlPlane)...)
return resources
}
@@ -258,12 +261,42 @@ func getKubeadmAddonResources(c client.Client, log logr.Logger, tenantControlPla
}
}
func getKonnectivityResources(c client.Client, tenantControlPlane kamajiv1alpha1.TenantControlPlane) []resources.Resource {
func getExternalKonnectivityResources(c client.Client, log logr.Logger, tcpReconcilerConfig TenantControlPlaneReconcilerConfig, tenantControlPlane kamajiv1alpha1.TenantControlPlane) []resources.Resource {
return []resources.Resource{
&konnectivity.EgressSelectorConfiguration{
&konnectivity.ServiceAccountResource{
Client: c,
Name: "konnectivity-sa",
},
&konnectivity.ClusterRoleBindingResource{
Client: c,
Name: "konnectivity-clusterrolebinding",
},
&konnectivity.ServiceResource{
Client: c,
Name: "konnectivity-service",
},
&konnectivity.Agent{
Client: c,
Name: "konnectivity-agent",
},
}
}
func getInternalKonnectivityResources(c client.Client, log logr.Logger, tcpReconcilerConfig TenantControlPlaneReconcilerConfig, tenantControlPlane kamajiv1alpha1.TenantControlPlane) []resources.Resource {
return []resources.Resource{
&konnectivity.EgressSelectorConfigurationResource{
Client: c,
Name: "konnectivity-egress-selector-configuration",
},
&konnectivity.CertificateResource{
Client: c,
Log: log,
Name: "konnectivity-certificate",
},
&konnectivity.KubeconfigResource{
Client: c,
Name: "konnectivity-kubeconfig",
},
}
}

View File

@@ -37,3 +37,6 @@ kamaji-kind-worker-push: kamaji-kind-worker-build
kamaji-kind-worker-join:
$(kind_path)/join-node.bash
kamaji-kind-worker-join-through-konnectivity:
$(kind_path)/join-node-konnectivity.bash

View File

@@ -0,0 +1,34 @@
#!/bin/bash
set -e
# Constants
export DOCKER_IMAGE_NAME="clastix/kamaji-kind-worker"
# Variables
export KUBERNETES_VERSION=${1:-latest}
if [ -z $2 ]
then
MAPPING_PORT=""
else
MAPPING_PORT="-p ${2}:80"
fi
export KONNECTIVITY_PROXY_HOST=${3:-konnectiviy.local}
clear
echo "Welcome to join a new node through Konnectivity"
echo -ne "\nChecking right kubeconfig\n"
kubectl cluster-info
echo "Are you pointing to the right tenant control plane? (Type return to continue)"
read
JOIN_CMD="$(kubeadm --kubeconfig=/tmp/kubeconfig token create --print-join-command) --ignore-preflight-errors=SystemVerification"
echo "Deploying new node..."
KIND_IP=$(docker inspect kamaji-control-plane --format='{{.NetworkSettings.Networks.kind.IPAddress}}')
NODE=$(docker run -d --add-host $KONNECTIVITY_PROXY_HOST:$KIND_IP --privileged -v /lib/modules:/lib/modules:ro -v /var --net host $MAPPING_PORT $DOCKER_IMAGE_NAME:$KUBERNETES_VERSION)
sleep 10
echo "Joining new node..."
docker exec -e JOIN_CMD="$JOIN_CMD" $NODE /bin/bash -c "$JOIN_CMD"

View File

@@ -23,10 +23,14 @@ nodes:
- containerPort: 443
hostPort: 443
protocol: TCP
## expose port 31132 of the node to port 31132 on the host for konnectivity
- containerPort: 31132
hostPort: 31132
protocol: TCP
## expose port 31443 of the node to port 31443 on the host
- containerPort: 31443
hostPort: 31443
protocol: TCP
protocol: TCP
## expose port 6443 of the node to port 8443 on the host
- containerPort: 6443
hostPort: 8443

View File

@@ -73,6 +73,23 @@ spec:
EOF
```
If workers are not reachable from tenant control plane, konnectivity can be enabled (it is by default):
```yaml
...
addons:
konnectivity:
enabled: true
proxyHost: "172.18.0.2"
proxyPort: 31132
...
```
`proxyHost` is the address where konnectivity proxy server will be running. Konnectivity works as sidecar container into the tenant control plane pod. If no value is specified, it will take tenant IP.
`proxyPort` is the port where konnectivity proxy server will be running. (default `8132`)
```bash
kubectl create namespace ${TENANT_NAMESPACE}
kubectl apply -f ${TENANT_NAMESPACE}-${TENANT_NAME}-tcp.yaml

View File

@@ -102,3 +102,16 @@ addons:
addons:
kubeProxy: {}
```
### Konnectivity
```yaml
addons:
konnectivity:
proxyPort: 31132 # mandatory
proxyHost: "172.18.0.2"
allowAddressAsExternalIP: false
serviceType: NodePort # mandatory
version: v0.0.31
serverImage: us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-server
agentImage: us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-agent

1
go.mod
View File

@@ -16,6 +16,7 @@ require (
google.golang.org/grpc v1.43.0
k8s.io/api v0.23.5
k8s.io/apimachinery v0.23.5
k8s.io/apiserver v0.23.5
k8s.io/client-go v0.23.5
k8s.io/cluster-bootstrap v0.0.0
k8s.io/component-base v0.23.5

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,8 @@ type CACertificate struct {
}
func (r *CACertificate) ShouldStatusBeUpdated(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Status.Certificates.CA.SecretName != r.resource.GetName()
return tenantControlPlane.Status.Certificates.CA.SecretName != r.resource.GetName() ||
tenantControlPlane.Status.Certificates.CA.ResourceVersion != r.resource.ResourceVersion
}
func (r *CACertificate) ShouldCleanup(plane *kamajiv1alpha1.TenantControlPlane) bool {
@@ -74,6 +75,7 @@ func (r *CACertificate) GetName() string {
func (r *CACertificate) UpdateTenantControlPlaneStatus(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
tenantControlPlane.Status.Certificates.CA.LastUpdate = metav1.Now()
tenantControlPlane.Status.Certificates.CA.SecretName = r.resource.GetName()
tenantControlPlane.Status.Certificates.CA.ResourceVersion = r.resource.ResourceVersion
return nil
}

View File

@@ -25,9 +25,17 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
"github.com/clastix/kamaji/internal/resources/konnectivity"
"github.com/clastix/kamaji/internal/utilities"
)
const (
konnectivityEgressSelectorConfigurationPath = "/etc/kubernetes/konnectivity/configurations/egress-selector-configuration.yaml"
konnectivityServerName = "konnectivity-server"
konnectivityServerPath = "/run/konnectivity"
konnectivityUDSName = "konnectivity-uds"
)
type KubernetesDeploymentResource struct {
resource *appsv1.Deployment
Client client.Client
@@ -49,7 +57,7 @@ func (r *KubernetesDeploymentResource) ShouldCleanup(plane *kamajiv1alpha1.Tenan
}
func (r *KubernetesDeploymentResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {
return tenantControlPlane.Spec.Addons.Konnectivity != nil, nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil, nil
}
func (r *KubernetesDeploymentResource) Define(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
@@ -548,6 +556,10 @@ func (r *KubernetesDeploymentResource) CreateOrUpdate(ctx context.Context, tenan
},
}
if err := r.reconcileKonnectivity(&r.resource.Spec.Template.Spec, *tenantControlPlane); err != nil {
return err
}
return controllerutil.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme())
})
}
@@ -573,6 +585,7 @@ func (r *KubernetesDeploymentResource) UpdateTenantControlPlaneStatus(ctx contex
DeploymentStatus: r.resource.Status,
Name: r.resource.GetName(),
Namespace: r.resource.GetNamespace(),
LastUpdate: metav1.Now(),
}
return nil
@@ -605,7 +618,7 @@ func (r *KubernetesDeploymentResource) isNotReady() bool {
}
func (r *KubernetesDeploymentResource) reconcileKonnectivity(podSpec *corev1.PodSpec, tenantControlPlane kamajiv1alpha1.TenantControlPlane) error {
if tenantControlPlane.Spec.Addons.Konnectivity != nil {
if tenantControlPlane.Spec.Addons.Konnectivity == nil {
return nil
}

View File

@@ -34,7 +34,7 @@ func (r *Agent) ShouldStatusBeUpdated(ctx context.Context, tenantControlPlane *k
}
func (r *Agent) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Spec.Addons.Konnectivity != nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil
}
func (r *Agent) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {

View File

@@ -42,7 +42,7 @@ func (r *CertificateResource) ShouldStatusBeUpdated(ctx context.Context, tenantC
}
func (r *CertificateResource) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Spec.Addons.Konnectivity != nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil
}
func (r *CertificateResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {

View File

@@ -29,7 +29,7 @@ func (r *ClusterRoleBindingResource) ShouldStatusBeUpdated(ctx context.Context,
}
func (r *ClusterRoleBindingResource) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Spec.Addons.Konnectivity != nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil
}
func (r *ClusterRoleBindingResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {

View File

@@ -0,0 +1,19 @@
package konnectivity
const (
AgentName = "konnectivity-agent"
CertCommonName = "system:konnectivity-server"
agentTokenName = "konnectivity-agent-token"
apiServerAPIVersion = "apiserver.k8s.io/v1beta1"
certExpirationDelayYears = 10
certOrganization = "system:master"
defaultClusterName = "kubernetes"
defaultUDSName = "/run/konnectivity/konnectivity-server.socket"
egressSelectorConfigurationKind = "EgressSelectorConfiguration"
egressSelectorConfigurationName = "cluster"
konnectivityCertAndKeyBaseName = "konnectivity"
konnectivityKubeconfigFileName = "konnectivity-server.conf"
kubeconfigAPIVersion = "v1"
roleAuthDelegator = "system:auth-delegator"
)

View File

@@ -35,7 +35,7 @@ func (r *EgressSelectorConfigurationResource) Define(ctx context.Context, tenant
}
func (r *EgressSelectorConfigurationResource) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Spec.Addons.Konnectivity != nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil
}
func (r *EgressSelectorConfigurationResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {

View File

@@ -32,7 +32,7 @@ func (r *KubeconfigResource) ShouldStatusBeUpdated(ctx context.Context, tenantCo
}
func (r *KubeconfigResource) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Spec.Addons.Konnectivity != nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil
}
func (r *KubeconfigResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {

View File

@@ -30,7 +30,7 @@ func (r *ServiceAccountResource) ShouldStatusBeUpdated(ctx context.Context, tena
}
func (r *ServiceAccountResource) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Spec.Addons.Konnectivity != nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil
}
func (r *ServiceAccountResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {

View File

@@ -10,7 +10,6 @@ import (
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -28,6 +27,18 @@ type ServiceResource struct {
}
func (r *ServiceResource) ShouldStatusBeUpdated(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
if tenantControlPlane.Status.Addons.Konnectivity.Service.Name != r.resource.GetName() {
return true
}
if tenantControlPlane.Status.Addons.Konnectivity.Service.Namespace != r.resource.GetNamespace() {
return true
}
if tenantControlPlane.Status.Addons.Konnectivity.Service.Port != r.resource.Spec.Ports[0].Port {
return true
}
if len(r.resource.Status.Conditions) != len(tenantControlPlane.Status.Addons.Konnectivity.Service.Conditions) {
return true
}
@@ -60,7 +71,7 @@ func (r *ServiceResource) ShouldStatusBeUpdated(ctx context.Context, tenantContr
}
func (r *ServiceResource) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
return tenantControlPlane.Spec.Addons.Konnectivity != nil
return tenantControlPlane.Spec.Addons.Konnectivity == nil
}
func (r *ServiceResource) CleanUp(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (bool, error) {
@@ -86,7 +97,7 @@ func (r *ServiceResource) UpdateTenantControlPlaneStatus(ctx context.Context, te
return nil
}
tenantControlPlane.Status.Addons.Konnectivity.Service = corev1.ServiceStatus{}
tenantControlPlane.Status.Addons.Konnectivity.Service = kamajiv1alpha1.KubernetesServiceStatus{}
tenantControlPlane.Status.Addons.Konnectivity.Enabled = false
return nil
@@ -108,8 +119,7 @@ func (r *ServiceResource) CreateOrUpdate(ctx context.Context, tenantControlPlane
}
func (r *ServiceResource) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) func() error {
namespacedName := k8stypes.NamespacedName{Namespace: r.resource.GetNamespace(), Name: r.resource.GetName()}
address, _ := tenantControlPlane.GetAddress(ctx, r.Client, namespacedName, tenantControlPlane.Spec.Addons.Konnectivity.ProxyHost)
address, _ := tenantControlPlane.GetKonnectivityServerAddress(ctx, r.Client)
if address == "" {
address = tenantControlPlane.Spec.NetworkProfile.Address
}
@@ -140,10 +150,10 @@ func (r *ServiceResource) mutate(ctx context.Context, tenantControlPlane *kamaji
case utilities.IsValidIP(address):
isIP = true
case !utilities.IsValidHostname(address):
return fmt.Errorf("%s is not a valid address for Konnectivity proxy server.", address)
return fmt.Errorf("%s is not a valid address for konnectivity proxy server", address)
}
switch tenantControlPlane.Spec.ControlPlane.Service.ServiceType {
switch tenantControlPlane.Spec.Addons.Konnectivity.ServiceType {
case kamajiv1alpha1.ServiceTypeLoadBalancer:
r.resource.Spec.Type = corev1.ServiceTypeLoadBalancer

View File

@@ -6,6 +6,8 @@ package utilities
import (
"bytes"
"fmt"
"net"
"regexp"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/json"
@@ -56,3 +58,24 @@ func EncondeToYaml(o runtime.Object) ([]byte, error) {
return buf.Bytes(), err
}
// IsValidIP checks if the given argument is an IP.
func IsValidIP(ip string) bool {
return net.ParseIP(ip) != nil
}
// IsValidHostname checks if the given argument is a valid hostname.
func IsValidHostname(hostname string) bool {
pattern := "^([a-z0-9]|[a-z0-9][a-z0-9-]{0,61}[a-z0-9])(\\.([a-z0-9]|[a-z0-9][a-z0-9-]{0,61}[a-z0-9]))*$"
return validateRegex(pattern, hostname)
}
func validateRegex(pattern string, value string) bool {
isFound, err := regexp.MatchString(pattern, value)
if err != nil {
return false
}
return isFound
}