github.com/IBM-Blockchain/fabric-operator@v1.0.4/pkg/util/util.go (about) 1 /* 2 * Copyright contributors to the Hyperledger Fabric Operator project 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package util 20 21 import ( 22 "context" 23 "crypto/rand" 24 "crypto/tls" 25 "crypto/x509" 26 "encoding/base64" 27 "encoding/json" 28 "encoding/pem" 29 "fmt" 30 "io/ioutil" 31 "math/big" 32 "net" 33 "net/http" 34 "net/url" 35 "os" 36 "path" 37 "path/filepath" 38 "strings" 39 "time" 40 41 "github.com/IBM-Blockchain/fabric-operator/pkg/k8s/clientset" 42 routev1 "github.com/openshift/api/route/v1" 43 "github.com/pkg/errors" 44 appsv1 "k8s.io/api/apps/v1" 45 corev1 "k8s.io/api/core/v1" 46 networkingv1 "k8s.io/api/networking/v1" 47 networkingv1beta1 "k8s.io/api/networking/v1beta1" 48 rbacv1 "k8s.io/api/rbac/v1" 49 extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 50 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 51 "k8s.io/apimachinery/pkg/types" 52 "k8s.io/apimachinery/pkg/util/strategicpatch" 53 "k8s.io/apimachinery/pkg/util/yaml" 54 "k8s.io/apimachinery/pkg/version" 55 "k8s.io/client-go/rest" 56 k8sclient "sigs.k8s.io/controller-runtime/pkg/client" 57 yaml1 "sigs.k8s.io/yaml" 58 ) 59 60 const ( 61 maximumCRNameLength = 32 62 ) 63 64 func ConvertYamlFileToJson(file string) ([]byte, error) { 65 absfilepath, err := filepath.Abs(file) 66 if err != nil { 67 return nil, err 68 } 69 bytes, err := ioutil.ReadFile(filepath.Clean(absfilepath)) 70 if err != nil { 71 return nil, err 72 } 73 74 return yaml.ToJSON(bytes) 75 } 76 77 func GetContainerFromFile(file string) (*corev1.Container, error) { 78 jsonBytes, err := ConvertYamlFileToJson(file) 79 if err != nil { 80 return nil, err 81 } 82 83 cont := &corev1.Container{} 84 err = json.Unmarshal(jsonBytes, &cont) 85 if err != nil { 86 return nil, err 87 } 88 89 return cont, nil 90 } 91 92 func GetPVCFromFile(file string) (*corev1.PersistentVolumeClaim, error) { 93 jsonBytes, err := ConvertYamlFileToJson(file) 94 if err != nil { 95 return nil, err 96 } 97 98 pvc := &corev1.PersistentVolumeClaim{} 99 err = json.Unmarshal(jsonBytes, &pvc) 100 if err != nil { 101 return nil, err 102 } 103 104 return pvc, nil 105 } 106 107 func GetRoleFromFile(file string) (*rbacv1.Role, error) { 108 jsonBytes, err := ConvertYamlFileToJson(file) 109 if err != nil { 110 return nil, err 111 } 112 113 role := &rbacv1.Role{} 114 err = json.Unmarshal(jsonBytes, &role) 115 if err != nil { 116 return nil, err 117 } 118 119 return role, nil 120 } 121 122 func GetClusterRoleFromFile(file string) (*rbacv1.ClusterRole, error) { 123 jsonBytes, err := ConvertYamlFileToJson(file) 124 if err != nil { 125 return nil, err 126 } 127 128 role := &rbacv1.ClusterRole{} 129 err = json.Unmarshal(jsonBytes, &role) 130 if err != nil { 131 return nil, err 132 } 133 134 return role, nil 135 } 136 137 func GetRoleBindingFromFile(file string) (*rbacv1.RoleBinding, error) { 138 jsonBytes, err := ConvertYamlFileToJson(file) 139 if err != nil { 140 return nil, err 141 } 142 143 rolebinding := &rbacv1.RoleBinding{} 144 err = json.Unmarshal(jsonBytes, &rolebinding) 145 if err != nil { 146 return nil, err 147 } 148 149 return rolebinding, nil 150 } 151 152 func GetClusterRoleBindingFromFile(file string) (*rbacv1.ClusterRoleBinding, error) { 153 jsonBytes, err := ConvertYamlFileToJson(file) 154 if err != nil { 155 return nil, err 156 } 157 158 rolebinding := &rbacv1.ClusterRoleBinding{} 159 err = json.Unmarshal(jsonBytes, &rolebinding) 160 if err != nil { 161 return nil, err 162 } 163 164 return rolebinding, nil 165 } 166 167 func GetServiceAccountFromFile(file string) (*corev1.ServiceAccount, error) { 168 jsonBytes, err := ConvertYamlFileToJson(file) 169 if err != nil { 170 return nil, err 171 } 172 173 serviceaccount := &corev1.ServiceAccount{} 174 err = json.Unmarshal(jsonBytes, &serviceaccount) 175 if err != nil { 176 return nil, err 177 } 178 179 return serviceaccount, nil 180 } 181 182 func GetDeploymentFromFile(file string) (*appsv1.Deployment, error) { 183 jsonBytes, err := ConvertYamlFileToJson(file) 184 if err != nil { 185 return nil, err 186 } 187 188 dep := &appsv1.Deployment{} 189 err = json.Unmarshal(jsonBytes, &dep) 190 if err != nil { 191 return nil, err 192 } 193 194 return dep, nil 195 } 196 197 func GetServiceFromFile(file string) (*corev1.Service, error) { 198 jsonBytes, err := ConvertYamlFileToJson(file) 199 if err != nil { 200 return nil, err 201 } 202 203 svc := &corev1.Service{} 204 err = json.Unmarshal(jsonBytes, &svc) 205 if err != nil { 206 return nil, err 207 } 208 209 return svc, nil 210 } 211 212 func GetConfigMapFromFile(file string) (*corev1.ConfigMap, error) { 213 absfilepath, err := filepath.Abs(file) 214 if err != nil { 215 return nil, err 216 } 217 bytes, err := ioutil.ReadFile(filepath.Clean(absfilepath)) 218 if err != nil { 219 return nil, err 220 } 221 cm := &corev1.ConfigMap{} 222 err = yaml1.Unmarshal(bytes, cm) 223 if err != nil { 224 return nil, err 225 } 226 227 return cm, nil 228 } 229 230 func GetRouteFromFile(file string) (*routev1.Route, error) { 231 jsonBytes, err := ConvertYamlFileToJson(file) 232 if err != nil { 233 return nil, err 234 } 235 236 route := &routev1.Route{} 237 err = json.Unmarshal(jsonBytes, &route) 238 if err != nil { 239 return nil, err 240 } 241 242 return route, nil 243 } 244 245 func GetIngressFromFile(file string) (*networkingv1.Ingress, error) { 246 jsonBytes, err := ConvertYamlFileToJson(file) 247 if err != nil { 248 return nil, err 249 } 250 251 ingress := &networkingv1.Ingress{} 252 err = json.Unmarshal(jsonBytes, &ingress) 253 if err != nil { 254 return nil, err 255 } 256 257 return ingress, nil 258 } 259 260 func GetIngressv1beta1FromFile(file string) (*networkingv1beta1.Ingress, error) { 261 jsonBytes, err := ConvertYamlFileToJson(file) 262 if err != nil { 263 return nil, err 264 } 265 266 ingress := &networkingv1beta1.Ingress{} 267 err = json.Unmarshal(jsonBytes, &ingress) 268 if err != nil { 269 return nil, err 270 } 271 272 return ingress, nil 273 } 274 275 func GetSecretFromFile(file string) (*corev1.Secret, error) { 276 jsonBytes, err := ConvertYamlFileToJson(file) 277 if err != nil { 278 return nil, err 279 } 280 281 secret := &corev1.Secret{} 282 err = json.Unmarshal(jsonBytes, &secret) 283 if err != nil { 284 return nil, err 285 } 286 287 return secret, nil 288 } 289 290 func GetCRDFromFile(file string) (*extv1.CustomResourceDefinition, error) { 291 jsonBytes, err := ConvertYamlFileToJson(file) 292 if err != nil { 293 return nil, err 294 } 295 296 crd := &extv1.CustomResourceDefinition{} 297 err = json.Unmarshal(jsonBytes, &crd) 298 if err != nil { 299 return nil, err 300 } 301 302 return crd, nil 303 } 304 305 func GetPodFromFile(file string) (*corev1.Pod, error) { 306 jsonBytes, err := ConvertYamlFileToJson(file) 307 if err != nil { 308 return nil, err 309 } 310 311 pod := &corev1.Pod{} 312 err = json.Unmarshal(jsonBytes, &pod) 313 if err != nil { 314 return nil, err 315 } 316 317 return pod, nil 318 } 319 320 func GetResourcePatch(current, new *corev1.ResourceRequirements) (*corev1.ResourceRequirements, error) { 321 currentBytes, err := json.Marshal(current) 322 if err != nil { 323 return nil, err 324 } 325 326 newBytes, err := json.Marshal(new) 327 if err != nil { 328 return nil, err 329 } 330 331 patchBytes, err := strategicpatch.StrategicMergePatch(currentBytes, newBytes, corev1.ResourceRequirements{}) 332 if err != nil { 333 return nil, err 334 } 335 336 update := &corev1.ResourceRequirements{} 337 err = json.Unmarshal(patchBytes, update) 338 if err != nil { 339 return nil, err 340 } 341 342 return update, nil 343 } 344 345 func IgnoreAlreadyExistError(err error) error { 346 if !strings.Contains(err.Error(), "already exists") { 347 return err 348 } 349 return nil 350 } 351 352 // Ignore benign error 353 func IgnoreOutdatedResourceVersion(err error) error { 354 if err == nil { 355 return nil 356 } 357 358 if !strings.Contains(err.Error(), "please apply your changes to the latest version and try again") { 359 return err 360 } 361 362 return nil 363 } 364 365 func EnvExists(envs []corev1.EnvVar, key string) bool { 366 for _, ele := range envs { 367 if ele.Name == key { 368 return true 369 } 370 } 371 return false 372 } 373 374 func GetEnvValue(envs []corev1.EnvVar, key string) string { 375 for _, ele := range envs { 376 if ele.Name == key { 377 return ele.Value 378 } 379 } 380 return "" 381 } 382 383 func ReplaceEnvIfDiff(envs []corev1.EnvVar, key, replace string) ([]corev1.EnvVar, bool) { 384 var updated bool 385 for _, ele := range envs { 386 if ele.Name == key { 387 oldValue := ele.Value 388 if oldValue != replace { 389 envs = UpdateEnvVar(ele.Name, replace, envs) 390 updated = true 391 } 392 } 393 } 394 return envs, updated 395 } 396 397 func AppendStringIfMissing(array []string, newEle string) []string { 398 for _, ele := range array { 399 if ele == newEle { 400 return array 401 } 402 } 403 return append(array, newEle) 404 } 405 406 func AppendEnvIfMissing(envs []corev1.EnvVar, env corev1.EnvVar) []corev1.EnvVar { 407 for _, ele := range envs { 408 if ele.Name == env.Name { 409 return envs 410 } 411 } 412 return append(envs, env) 413 } 414 415 func AppendPullSecretIfMissing(pullSecrets []corev1.LocalObjectReference, pullSecret string) []corev1.LocalObjectReference { 416 for _, ps := range pullSecrets { 417 if ps.Name == pullSecret { 418 return pullSecrets 419 } 420 } 421 return append(pullSecrets, corev1.LocalObjectReference{Name: pullSecret}) 422 } 423 424 func AppendEnvIfMissingOverrideIfPresent(envs []corev1.EnvVar, env corev1.EnvVar) []corev1.EnvVar { 425 for index, ele := range envs { 426 if ele.Name == env.Name { 427 ele.Value = env.Value 428 envs[index] = ele 429 return envs 430 } 431 } 432 return append(envs, env) 433 } 434 435 func AppendConfigMapFromSourceIfMissing(envFroms []corev1.EnvFromSource, envFrom corev1.EnvFromSource) []corev1.EnvFromSource { 436 for _, ele := range envFroms { 437 if ele.ConfigMapRef.Name == envFrom.ConfigMapRef.Name { 438 return envFroms 439 } 440 } 441 return append(envFroms, envFrom) 442 } 443 444 func AppendVolumeIfMissing(volumes []corev1.Volume, volume corev1.Volume) []corev1.Volume { 445 for _, v := range volumes { 446 if v.Name == volume.Name { 447 return volumes 448 } 449 } 450 return append(volumes, volume) 451 } 452 453 func AppendVolumeMountIfMissing(volumeMounts []corev1.VolumeMount, volumeMount corev1.VolumeMount) []corev1.VolumeMount { 454 for _, v := range volumeMounts { 455 if v.Name == volumeMount.Name { 456 if v.MountPath == volumeMount.MountPath { 457 return volumeMounts 458 } 459 } 460 } 461 return append(volumeMounts, volumeMount) 462 } 463 464 func AppendVolumeMountWithSubPathIfMissing(volumeMounts []corev1.VolumeMount, volumeMount corev1.VolumeMount) []corev1.VolumeMount { 465 for _, v := range volumeMounts { 466 if v.Name == volumeMount.Name { 467 if v.SubPath == volumeMount.SubPath { 468 return volumeMounts 469 } 470 } 471 } 472 return append(volumeMounts, volumeMount) 473 } 474 475 func AppendContainerIfMissing(containers []corev1.Container, container corev1.Container) []corev1.Container { 476 for _, c := range containers { 477 if c.Name == container.Name { 478 return containers 479 } 480 } 481 return append(containers, container) 482 } 483 484 func AppendImagePullSecretIfMissing(imagePullSecrets []corev1.LocalObjectReference, imagePullSecret corev1.LocalObjectReference) []corev1.LocalObjectReference { 485 if imagePullSecret.Name == "" { 486 return imagePullSecrets 487 } 488 for _, i := range imagePullSecrets { 489 if i.Name == imagePullSecret.Name { 490 return imagePullSecrets 491 } 492 } 493 return append(imagePullSecrets, imagePullSecret) 494 } 495 496 func UpdateEnvVar(name string, value string, envs []corev1.EnvVar) []corev1.EnvVar { 497 newEnvs := []corev1.EnvVar{} 498 for _, e := range envs { 499 if e.Name == name { 500 e.Value = value 501 } 502 newEnvs = append(newEnvs, e) 503 } 504 return newEnvs 505 } 506 507 func ValidationChecks(typedata metav1.TypeMeta, metadata metav1.ObjectMeta, expectedKind string, maxNameLength *int) error { 508 maxlength := maximumCRNameLength 509 510 if maxNameLength != nil { 511 maxlength = *maxNameLength 512 } 513 514 if len(metadata.Name) > maxlength { 515 return fmt.Errorf("The instance name '%s' is too long, the name must be less than or equal to %d characters", metadata.Name, maxlength) 516 } 517 518 if typedata.Kind != "" { 519 if typedata.Kind != expectedKind { 520 return fmt.Errorf("The instance '%s' is of kind %s not an %s kind resource, please check to make sure there are no name collisions across resources", metadata.Name, typedata.Kind, expectedKind) 521 } 522 } 523 524 return nil 525 } 526 527 func SelectRandomValue(values []string) string { 528 if len(values) == 0 { 529 return "" 530 } 531 randValue, _ := rand.Int(rand.Reader, big.NewInt(int64(len(values)))) 532 return values[randValue.Int64()] 533 } 534 535 type Client interface { 536 Get(ctx context.Context, namespacedName types.NamespacedName, obj k8sclient.Object) error 537 List(ctx context.Context, list k8sclient.ObjectList, opts ...k8sclient.ListOption) error 538 } 539 540 func GetZone(client Client) string { 541 nodeList := &corev1.NodeList{} 542 err := client.List(context.TODO(), nodeList) 543 if err != nil { 544 return "" 545 } 546 547 zones := []string{} 548 for _, node := range nodeList.Items { 549 zone := node.ObjectMeta.Labels["topology.kubernetes.io/zone"] 550 zones = append(zones, zone) 551 } 552 553 return SelectRandomValue(zones) 554 } 555 556 func GetRegion(client Client) string { 557 nodeList := &corev1.NodeList{} 558 err := client.List(context.TODO(), nodeList) 559 if err != nil { 560 return "" 561 } 562 563 regions := []string{} 564 for _, node := range nodeList.Items { 565 region := node.ObjectMeta.Labels["topology.kubernetes.io/region"] 566 regions = append(regions, region) 567 } 568 569 return SelectRandomValue(regions) 570 } 571 572 func ContainsValue(find string, in []string) bool { 573 for _, value := range in { 574 if find == value { 575 return true 576 } 577 } 578 return false 579 } 580 581 func ValidateZone(client Client, requestedZone string) error { 582 nodeList := &corev1.NodeList{} 583 err := client.List(context.TODO(), nodeList) 584 if err != nil { 585 return nil 586 } 587 zones := []string{} 588 for _, node := range nodeList.Items { 589 zone := node.ObjectMeta.Labels["topology.kubernetes.io/zone"] 590 zones = append(zones, zone) 591 zone = node.ObjectMeta.Labels["failure-domain.beta.kubernetes.io/zone"] 592 zones = append(zones, zone) 593 zone = node.ObjectMeta.Labels["ibm-cloud.kubernetes.io/zone"] 594 zones = append(zones, zone) 595 } 596 valueFound := ContainsValue(requestedZone, zones) 597 if !valueFound { 598 return errors.Errorf("Zone '%s' is not a valid zone", requestedZone) 599 } 600 return nil 601 } 602 603 func ValidateRegion(client Client, requestedRegion string) error { 604 nodeList := &corev1.NodeList{} 605 err := client.List(context.TODO(), nodeList) 606 if err != nil { 607 return nil 608 } 609 regions := []string{} 610 for _, node := range nodeList.Items { 611 region := node.ObjectMeta.Labels["topology.kubernetes.io/region"] 612 regions = append(regions, region) 613 region = node.ObjectMeta.Labels["failure-domain.beta.kubernetes.io/region"] 614 regions = append(regions, region) 615 region = node.ObjectMeta.Labels["ibm-cloud.kubernetes.io/region"] 616 regions = append(regions, region) 617 } 618 valueFound := ContainsValue(requestedRegion, regions) 619 if !valueFound { 620 return errors.Errorf("Region '%s' is not a valid region", requestedRegion) 621 } 622 return nil 623 } 624 625 func FileExists(path string) bool { 626 if _, err := os.Stat(path); err == nil { 627 return true 628 } 629 return false 630 } 631 632 func EnsureDir(dirName string) error { 633 err := os.MkdirAll(dirName, 0750) 634 635 if err == nil || os.IsExist(err) { 636 return nil 637 } else { 638 return err 639 } 640 } 641 642 func GetResourceVerFromSecret(client Client, name, namespace string) (string, error) { 643 secret := &corev1.Secret{} 644 err := client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: namespace}, secret) 645 if err != nil { 646 return "", err 647 } 648 649 resourceVer := secret.ObjectMeta.ResourceVersion 650 return resourceVer, nil 651 } 652 653 func JoinMaps(m1, m2 map[string][]byte) map[string][]byte { 654 joined := map[string][]byte{} 655 656 if m1 != nil { 657 for k, v := range m1 { 658 joined[k] = v 659 } 660 } 661 662 if m2 != nil { 663 for k, v := range m2 { 664 joined[k] = v 665 } 666 } 667 668 return joined 669 } 670 671 func PemStringToBytes(pem string) []byte { 672 return []byte(pem) 673 } 674 675 func FileToBytes(file string) ([]byte, error) { 676 data, err := ioutil.ReadFile(filepath.Clean(file)) 677 if err != nil { 678 return nil, errors.Wrapf(err, "failed to read file %s", file) 679 } 680 681 return data, nil 682 } 683 684 func Base64ToBytes(base64str string) ([]byte, error) { 685 data, err := base64.StdEncoding.DecodeString(base64str) 686 if err != nil { 687 // If base64 encoded string is padded with too many '=' at the 688 // end DecodeString will fail with error: "illegal base64 data at input byte ...". 689 // Need to try stripping of '=' at the one at a time and trying again until no more '=' 690 // left at that point return err. 691 692 if strings.HasSuffix(base64str, "=") { 693 base64str = base64str[:len(base64str)-1] 694 return Base64ToBytes(base64str) 695 } 696 return nil, errors.Wrapf(err, "failed to parse base64 string %s", base64str) 697 } 698 699 return data, nil 700 } 701 702 func BytesToBase64(b []byte) string { 703 data := base64.StdEncoding.EncodeToString(b) 704 705 return data 706 } 707 708 func GetCertificateFromPEMBytes(bytes []byte) (*x509.Certificate, error) { 709 block, _ := pem.Decode(bytes) 710 if block == nil { 711 return nil, errors.New("failed to decode PEM bytes") 712 } 713 714 cert, err := x509.ParseCertificate(block.Bytes) 715 if err != nil { 716 return nil, errors.Wrap(err, "failed to parse certificate") 717 } 718 719 return cert, nil 720 } 721 722 func WriteFile(file string, buf []byte, perm os.FileMode) error { 723 dir := path.Dir(file) 724 // Create the directory if it doesn't exist 725 if _, err := os.Stat(dir); os.IsNotExist(err) { 726 err = os.MkdirAll(dir, 0750) 727 if err != nil { 728 return errors.Wrapf(err, "Failed to create directory '%s' for file '%s'", dir, file) 729 } 730 } 731 return ioutil.WriteFile(file, buf, perm) 732 } 733 734 func CheckIfZoneOrRegionUpdated(oldValue string, newValue string) bool { 735 if (strings.ToLower(oldValue) != "select" && oldValue != "") && (strings.ToLower(newValue) != "select" && newValue != "") { 736 if oldValue != newValue { 737 return true 738 } 739 } 740 741 return false 742 } 743 744 func GenerateRandomString(length int) string { 745 const charset = "abcdefghijklmnopqrstuvwxyz" + 746 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 747 748 b := make([]byte, length) 749 for i := range b { 750 num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) 751 b[i] = charset[num.Int64()] 752 } 753 return string(b) 754 } 755 756 func ValidateHSMProxyURL(endpoint string) error { 757 parsedURL, err := url.Parse(endpoint) 758 if err != nil { 759 return err 760 } 761 762 address := strings.Split(parsedURL.Host, ":") 763 if len(address) < 2 { 764 return errors.New("must specify both IP address and port") 765 } 766 767 if address[0] == "" { 768 return errors.New("missing IP address") 769 } 770 771 if address[1] == "" { 772 return errors.New("missing port") 773 } 774 775 scheme := parsedURL.Scheme 776 if scheme != "tls" && scheme != "tcp" { 777 return fmt.Errorf("unsupported scheme '%s', only tcp and tls are supported", scheme) 778 } 779 780 if !IsTCPReachable(parsedURL.Host) { 781 return fmt.Errorf("Unable to reach HSM endpoint: %s", parsedURL.Host) 782 } 783 return nil 784 } 785 786 // func HealthCheck(caURL *url.URL, cert []byte) error { 787 func HealthCheck(healthURL string, cert []byte, timeout time.Duration) error { 788 rootCertPool := x509.NewCertPool() 789 rootCertPool.AppendCertsFromPEM(cert) 790 791 transport := http.DefaultTransport 792 transport.(*http.Transport).TLSClientConfig = &tls.Config{ 793 RootCAs: rootCertPool, 794 MinVersion: tls.VersionTLS12, // TLS 1.2 recommended, TLS 1.3 (current latest version) encouraged 795 } 796 797 client := http.Client{ 798 Transport: &http.Transport{ 799 IdleConnTimeout: timeout, 800 Dial: (&net.Dialer{ 801 Timeout: timeout, 802 KeepAlive: timeout, 803 }).Dial, 804 TLSHandshakeTimeout: timeout / 2, 805 TLSClientConfig: &tls.Config{ 806 RootCAs: rootCertPool, 807 MinVersion: tls.VersionTLS12, // TLS 1.2 recommended, TLS 1.3 (current latest version) encouraged 808 }, 809 }, 810 } 811 812 ctx, cancel := context.WithTimeout(context.Background(), timeout) 813 defer cancel() 814 815 req, err := http.NewRequestWithContext(ctx, http.MethodGet, healthURL, nil) 816 if err != nil { 817 return errors.Wrap(err, "invalid http request") 818 } 819 820 resp, err := client.Do(req) 821 if err != nil { 822 return errors.Wrapf(err, "health check request failed") 823 } 824 825 if resp.StatusCode != http.StatusOK { 826 return errors.Wrapf(err, "failed health check, ca is not running") 827 } 828 829 return nil 830 } 831 832 func IsTCPReachable(url string) bool { 833 url = strings.Replace(url, "tcp://", "", -1) 834 url = strings.Replace(url, "tls://", "", -1) 835 836 conn, err := net.Dial("tcp", url) 837 if err != nil { 838 return false 839 } 840 841 defer conn.Close() 842 843 return true 844 } 845 846 func IntermediateSecretExists(client Client, namespace, secretName string) bool { 847 err := client.Get(context.TODO(), types.NamespacedName{ 848 Name: secretName, 849 Namespace: namespace}, &corev1.Secret{}) 850 if err != nil { 851 return false 852 } 853 854 return true 855 } 856 857 func IsSecretTLSCert(secretName string) bool { 858 if strings.HasSuffix(secretName, "-signcert") { 859 return strings.HasPrefix(secretName, "tls") 860 } else if strings.HasSuffix(secretName, "-ca-crypto") { 861 return true 862 } 863 864 return false 865 } 866 867 func IsSecretEcert(secretName string) bool { 868 if strings.HasSuffix(secretName, "-signcert") { 869 return strings.HasPrefix(secretName, "ecert") 870 } 871 872 return false 873 } 874 875 func ConvertSpec(in interface{}, out interface{}) error { 876 jsonBytes, err := yaml1.Marshal(in) 877 if err != nil { 878 return err 879 } 880 881 err = yaml1.Unmarshal(jsonBytes, out) 882 if err != nil { 883 return err 884 } 885 return nil 886 } 887 888 func FindStringInArray(str string, slice []string) bool { 889 for _, item := range slice { 890 if item == str { 891 return true 892 } 893 } 894 return false 895 } 896 897 func ConvertToJsonMessage(in interface{}) (*json.RawMessage, error) { 898 bytes, err := json.Marshal(in) 899 if err != nil { 900 return nil, err 901 } 902 903 jm := json.RawMessage(bytes) 904 return &jm, 905 906 nil 907 } 908 909 func GetNetworkPolicyFromFile(file string) (*networkingv1.NetworkPolicy, error) { 910 jsonBytes, err := ConvertYamlFileToJson(file) 911 if err != nil { 912 return nil, err 913 } 914 915 policy := &networkingv1.NetworkPolicy{} 916 err = json.Unmarshal(jsonBytes, &policy) 917 if err != nil { 918 return nil, err 919 } 920 921 return policy, nil 922 } 923 924 func GetServerVersion() (*version.Info, error) { 925 config, err := rest.InClusterConfig() 926 if err != nil { 927 return nil, errors.Wrap(err, "failed to get cluster config") 928 } 929 930 clientSet, err := clientset.New(config) 931 if err != nil { 932 return nil, errors.Wrap(err, "failed to get client") 933 } 934 935 version, err := clientSet.DiscoveryClient.ServerVersion() 936 if err != nil { 937 return nil, errors.Wrap(err, "failed to get version") 938 } 939 return version, nil 940 }