network.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. Copyright 2019 The Rook Authors. All rights reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6.     http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package v1
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "net"
  18. "strings"
  19. nadv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
  20. nadutils "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils"
  21. "github.com/pkg/errors"
  22. )
  23. // IsMultus get whether to use multus network provider
  24. func (n *NetworkSpec) IsMultus() bool {
  25. return n.Provider == NetworkProviderMultus
  26. }
  27. // IsHost get whether to use host network provider. This method also preserve
  28. // compatibility with the old HostNetwork field.
  29. func (n *NetworkSpec) IsHost() bool {
  30. return (n.HostNetwork && n.Provider == NetworkProviderDefault) || n.Provider == NetworkProviderHost
  31. }
  32. func ValidateNetworkSpec(clusterNamespace string, spec NetworkSpec) error {
  33. if spec.IsMultus() {
  34. if len(spec.Selectors) == 0 {
  35. return errors.Errorf("at least one network selector must be specified when using the %q network provider", NetworkProviderMultus)
  36. }
  37. if _, err := spec.GetNetworkSelection(clusterNamespace, CephNetworkPublic); err != nil {
  38. return errors.Wrap(err, "ceph public network selector provided for multus is invalid")
  39. }
  40. if _, err := spec.GetNetworkSelection(clusterNamespace, CephNetworkCluster); err != nil {
  41. return errors.Wrap(err, "ceph cluster network selector provided for multus is invalid")
  42. }
  43. }
  44. if !spec.AddressRanges.IsEmpty() {
  45. if !spec.IsMultus() && !spec.IsHost() {
  46. // TODO: be sure to update docs that AddressRanges can be specified for host networking as
  47. // well as multus so that the override configmap doesn't need to be set
  48. return errors.Errorf("network ranges can only be specified for %q and %q network providers", NetworkProviderHost, NetworkProviderMultus)
  49. }
  50. if spec.IsMultus() {
  51. if len(spec.AddressRanges.Public) > 0 && !spec.NetworkHasSelection(CephNetworkPublic) {
  52. return errors.Errorf("public address range can only be specified for multus if there is a public network selection")
  53. }
  54. if len(spec.AddressRanges.Cluster) > 0 && !spec.NetworkHasSelection(CephNetworkCluster) {
  55. return errors.Errorf("cluster address range can only be specified for multus if there is a cluster network selection")
  56. }
  57. }
  58. }
  59. if err := spec.AddressRanges.Validate(); err != nil {
  60. return err
  61. }
  62. return nil
  63. }
  64. func ValidateNetworkSpecUpdate(clusterNamespace string, oldSpec, newSpec NetworkSpec) error {
  65. // Allow an attempt to enable or disable host networking, but not other provider changes
  66. oldProvider := oldSpec.Provider
  67. newProvider := newSpec.Provider
  68. if oldProvider != newProvider && oldProvider != "host" && newProvider != "host" {
  69. return errors.Errorf("invalid update: network provider change from %q to %q is not allowed", oldProvider, newProvider)
  70. }
  71. return ValidateNetworkSpec(clusterNamespace, newSpec)
  72. }
  73. // NetworkHasSelection returns true if the given Ceph network has a selection.
  74. func (n *NetworkSpec) NetworkHasSelection(network CephNetworkType) bool {
  75. s, ok := n.Selectors[network]
  76. if !ok || s == "" {
  77. return false
  78. }
  79. return true
  80. }
  81. // GetNetworkSelection gets the network selection for a given Ceph network, or nil if the network
  82. // doesn't have a selection.
  83. func (n *NetworkSpec) GetNetworkSelection(clusterNamespace string, network CephNetworkType) (*nadv1.NetworkSelectionElement, error) {
  84. if !n.NetworkHasSelection(network) {
  85. return nil, nil // no selection for network
  86. }
  87. s := n.Selectors[network]
  88. // From documentation of the "k8s.v1.cni.cncf.io/network-status" annotation, valid JSON inputs
  89. // must be in list form, surrounded with brackets. The NAD utility library will only parse
  90. // list-format JSON input. However, old versions of Rook code allowed non-list JSON objects.
  91. // In order to support legacy users, make an attempt to turn single-JSON-object inputs into
  92. // len(1) lists so that they parse correctly by the util library. Do not advertise this
  93. // "feature" in documentation since it is not technically the correct format.
  94. if strings.HasPrefix(s, "{") && strings.HasSuffix(s, "}") {
  95. s = "[" + s + "]"
  96. }
  97. selection, err := nadutils.ParseNetworkAnnotation(s, clusterNamespace)
  98. if err != nil {
  99. return nil, errors.Wrapf(err, "failed to parse %q network selector %q", network, s)
  100. }
  101. if len(selection) != 1 {
  102. return nil, errors.Errorf("%q network selector %q has multiple (%d) selections, which is not supported", network, s, len(selection))
  103. }
  104. return selection[0], nil
  105. }
  106. // NetworkSelectionsToAnnotationValue converts NetworkAttachmentDefinition network selection
  107. // elements to an annotation value for the "k8s.v1.cni.cncf.io/networks" annotation key.
  108. func NetworkSelectionsToAnnotationValue(selections ...*nadv1.NetworkSelectionElement) (string, error) {
  109. reduced := []*nadv1.NetworkSelectionElement{}
  110. for _, s := range selections {
  111. if s != nil {
  112. reduced = append(reduced, s)
  113. }
  114. }
  115. if len(reduced) == 0 {
  116. return "", nil
  117. }
  118. b, err := json.Marshal(reduced)
  119. if err != nil {
  120. return "", errors.Wrap(err, "failed to convert network selections to annotation value")
  121. }
  122. return string(b), nil
  123. }
  124. func (n *AddressRangesSpec) IsEmpty() bool {
  125. return n == nil || len(n.Public) == 0 && len(n.Cluster) == 0
  126. }
  127. func (n *AddressRangesSpec) Validate() error {
  128. if n.IsEmpty() {
  129. return nil
  130. }
  131. allRanges := append(n.Public, n.Cluster...)
  132. invalid := []string{}
  133. for _, cidr := range allRanges {
  134. _, _, err := net.ParseCIDR(string(cidr))
  135. if err != nil {
  136. // returned err is "invalid CIDR: <addr>" & not more useful than invalid list below
  137. invalid = append(invalid, string(cidr))
  138. }
  139. }
  140. if len(invalid) == 0 {
  141. return nil
  142. }
  143. return fmt.Errorf("%d network ranges are invalid: %v", len(invalid), invalid)
  144. }
  145. // String turns a CIDR list into a comma-delimited string of CIDRs
  146. func (l *CIDRList) String() string {
  147. sl := []string{}
  148. for _, c := range *l {
  149. sl = append(sl, string(c))
  150. }
  151. return strings.Join(sl, ", ")
  152. }