---
- name: Network | Ensure either internal_ipv4 or internal_ipv6 is defined
  assert:
    that: or (.internal_ipv4 | empty | not) (.internal_ipv6 | empty | not)
    fail_msg: >-
      Either "internal_ipv4" or "internal_ipv6" must be specified. Both cannot be empty.

- name: Network | Ensure required network interfaces are present
  command: |
    {{- if .internal_ipv4 | empty | not }}
    if ! ip -o addr show | grep -q {{ .internal_ipv4 }}; then
      echo 'The specified IPv4 address is not assigned to any network interface.' >&2
      exit 1
    fi
    {{- end }}
    {{- if .internal_ipv6 | empty | not }}
    if ! ip -o addr show | grep -q {{ .internal_ipv6 }}; then
      echo 'The specified IPv6 address is not assigned to any network interface.' >&2
      exit 1
    fi
    {{- end }}

# https://kubernetes.io/docs/concepts/services-networking/dual-stack/
- name: Network | Validate dual-stack CIDR configuration
  run_once: true
  block:
    - name: Network | Check pod CIDR includes both IPv4 and IPv6
      when: .cni.pod_cidr | empty | not
      assert:
        that: .cni.pod_cidr | splitList "," | len | ge 2
        fail_msg: >-
          "cni.pod_cidr" must specify both IPv4 and IPv6 ranges, using either the format ipv4_cidr/ipv6_cidr or ipv4_cidr,ipv6_cidr.
    - name: Network | Check service CIDR includes both IPv4 and IPv6
      when: .cni.service_cidr | empty | not
      assert:
        that: .cni.service_cidr | splitList "," | len | ge 2
        fail_msg: >-
          "cni.service_cidr" must specify both IPv4 and IPv6 ranges, using either the format ipv4_cidr/ipv6_cidr or ipv4_cidr,ipv6_cidr.
    - name: Network | Ensure pod networking is properly configured for dual-stack
      when:
        - .cni.pod_cidr | empty | not
        - .cni.pod_cidr | splitList "," | len | eq 2
      assert:
        that:
          - .kubernetes.kube_version | semverCompare ">=v1.20.0"
          - .cni.pod_cidr | splitList "," | first | ipFamily | eq "IPv4"
          - .cni.pod_cidr | splitList "," | last | ipFamily | eq "IPv6"
        fail_msg: >-
          Dual-stack pod networking is only supported in Kubernetes v1.20.0 or newer.
    - name: Network | Ensure service networking is properly configured for dual-stack
      when:
        - .cni.service_cidr | empty | not
        - .cni.service_cidr | splitList "," | len | eq 2
      assert:
        that:
          - .kubernetes.kube_version | semverCompare ">=v1.20.0"
          - .cni.service_cidr | splitList "," | first | ipFamily | eq "IPv4"
          - .cni.service_cidr | splitList "," | last | ipFamily | eq "IPv6"
        fail_msg: >-
          Dual-stack service networking is only supported in Kubernetes v1.20.0 or newer.

- name: Network | Fail if the selected network plugin is not supported
  run_once: true
  when: .cni.type | empty | not
  assert:
    that: .cluster_require.require_network_plugin | has .cni.type
    fail_msg: >-
      The network plugin "{{ .cni.type }}" is not supported. Please select a supported network plugin.

# Note: This check is intentionally conservative. While it is technically possible to schedule more pods than the available addresses in the CIDR range (for example, if some pods use the host network), this cannot be reliably determined at provisioning time. This check ensures there is enough address space for the configured maximum pods per node.
# Note: IPv6-only scenarios are not checked here.
- name: Network | Ensure sufficient address space for all pods
  run_once: true
  when: .groups.k8s_cluster | default list | has .inventory_hostname
  block:
    - name: Network | Ensure enough IPv4 addresses are available for pods
      when: .cni.pod_cidr | default "10.233.64.0/18" | splitList "," | first | ipFamily | eq "IPv4"
      assert:
        that: le (.cni.max_pods | default 110) (sub (pow 2 (float64 (sub 32 (.cni.ipv4_mask_size | default 24)))) 2)
        fail_msg: >-
          The configured maximum number of pods per node exceeds the number of available IPv4 addresses in the pod CIDR range.
    - name: Network | Ensure enough IPv6 addresses are available for pods
      when: .cni.pod_cidr | default "10.233.64.0/18" | splitList "," | last | ipFamily | eq "IPv6"
      assert:
        that: le (.cni.max_pods | default 110) (sub (pow 2 (float64 (sub 128 (.cni.ipv4_mask_size | default 64)))) 2)
        fail_msg: >-
          The configured maximum number of pods per node exceeds the number of available IPv6 addresses in the pod CIDR range.

# https://github.com/alibaba/hybridnet/wiki/Getting-Started#install
- name: Network | Fail if Kubernetes version is too old for hybridnet
  run_once: true
  assert:
    that: .kubernetes.kube_version | semverCompare ">=v1.16.0"
    fail_msg: >-
      Hybridnet requires Kubernetes version 1.16.0 or newer.
  when:
    - .cni.type | eq "hybridnet"