code: def _upsert_security_group_rules(conf, security_groups):
      sgids = {sg.id for sg in security_groups.values()}
  
      # Update sgids to include user-specified security groups.
      # This is necessary if the user specifies the head node type's security
      # groups but not the worker's, or vice-versa.
      for node_type in conf["available_node_types"]:
          sgids.update(
              conf["available_node_types"][node_type].get(
                  "SecurityGroupIds", []
              )
          )
  
      # sort security group items for deterministic inbound rule config order
      # (mainly supports more precise stub-based boto3 unit testing)
      for node_type, sg in sorted(security_groups.items()):
          sg = security_groups[node_type]
          if not sg.ip_permissions:
              _update_inbound_rules(sg, sgids, conf)
  
imports: import copy
  import itertools
  import json
  import logging
  import os
  import time
  from collections import Counter
  from functools import lru_cache, partial
  from typing import Any, Dict, List, Optional, Set, Tuple
  import boto3
  import botocore
  from packaging.version import Version
  from ray.autoscaler._private.aws.cloudwatch.cloudwatch_helper import CloudwatchHelper
  from ray.autoscaler._private.aws.utils import LazyDefaultDict, handle_boto_error, resource_cache
  from ray.autoscaler._private.cli_logger import cf, cli_logger
  from ray.autoscaler._private.event_system import CreateClusterEvent, global_event_system
  from ray.autoscaler._private.providers import _PROVIDER_PRETTY_NAMES
  from ray.autoscaler._private.util import check_legacy_fields
  from ray.autoscaler.tags import NODE_TYPE_LEGACY_HEAD, NODE_TYPE_LEGACY_WORKER
label_desc: Use image node_id 23 for calling a global function with example usage: _upsert_security_group_rules(conf, security_groups) without return types