Repository: istio/istio
File: pilot/pkg/model/service.go (Go)

Code before:

type ServiceInfo struct {
	Service *workloadapi.Service
	// LabelSelectors for the Service. Note these are only used internally, not sent over XDS
	LabelSelector LabelSelector
	// PortNames provides a mapping of ServicePort -> port names. Note these are only used internally, not sent over XDS
	PortNames map[int32]ServicePortName
	// Source is the type that introduced this service.
	Source TypedObject
	// Scope of the service - either local or global based on namespace or service label matching
	Scope    ServiceScope
	Waypoint WaypointBindingStatus
	// MarshaledAddress contains the pre-marshaled representation.
	// Note: this is an Address -- not a Service.
	MarshaledAddress *anypb.Any
	// AsAddress contains a pre-created AddressInfo representation. This ensures we do not need repeated conversions on
	// the hotpath
	AsAddress AddressInfo
	// CreationTime is the time when the service was created. Note this is used internally only
	// for conflict resolution.
	CreationTime time.Time
}

func (i ServiceInfo) GetLabelSelector() map[string]string {
	return i.LabelSelector.Labels
}

func (i ServiceInfo) GetStatusTarget() TypedObject {
	return i.Source
}

type ConditionType string

const (
	WaypointBound    ConditionType = "istio.io/WaypointBound"
	ZtunnelAccepted  ConditionType = "ZtunnelAccepted"
	WaypointAccepted ConditionType = "WaypointAccepted"
)

type ConditionSet = map[ConditionType]*Condition

type Condition struct {
	ObservedGeneration int64
	Reason             string
	Message            string
	Status             bool
}

func (c *Condition) Equals(v *Condition) bool {
	return c.ObservedGeneration == v.ObservedGeneration &&
		c.Reason == v.Reason &&

Review comment (suggestion):
IMO, it would be great to have CreationTime in the workloadapi.Service instead. maybe out of scope for your PR, but I think ztunnel should make use of the creationTime of services.

When resolving a hostname from our service registry in the DNS proxy, if there is no more specific match (from the client's namespace for instance) we eventually just take "first" but I believe that is relative to how services were added to our internal data structures. Ideally, first would always mean the oldest definition for a host name.

To be fair it's still not perfect, since someone could add a new hostname to an old service entry, and then the definition of first would shift suddenly but it seems more correct and consistent than the existing behavior.

Code after:

type ServicePortName struct {
	PortName       string
	TargetPortName string
}

type ServiceInfo struct {
	Service *workloadapi.Service
	// LabelSelectors for the Service. Note these are only used internally, not sent over XDS
	LabelSelector LabelSelector
	// PortNames provides a mapping of ServicePort -> port names. Note these are only used internally, not sent over XDS
	PortNames map[int32]ServicePortName
	// Source is the type that introduced this service.
	Source TypedObject
	// Scope of the service - either local or global based on namespace or service label matching
	Scope    ServiceScope
	Waypoint WaypointBindingStatus
	// MarshaledAddress contains the pre-marshaled representation.
	// Note: this is an Address -- not a Service.
	MarshaledAddress *anypb.Any
	// AsAddress contains a pre-created AddressInfo representation. This ensures we do not need repeated conversions on
	// the hotpath
	AsAddress AddressInfo
	// CreationTime is the time when the service was created. Note this is used internally only
	// for conflict resolution.
	CreationTime time.Time
}

func (i ServiceInfo) GetLabelSelector() map[string]string {
	return i.LabelSelector.Labels
}

func (i ServiceInfo) GetStatusTarget() TypedObject {
	return i.Source
}

type ConditionType string

const (
	WaypointBound    ConditionType = "istio.io/WaypointBound"
	ZtunnelAccepted  ConditionType = "ZtunnelAccepted"
	WaypointAccepted ConditionType = "WaypointAccepted"
	// WaypointMissing is set on a ServiceEntry with a wildcard hostname and not bound to a waypoint.
	// It is used to inform the user that the ServiceEntry will not be active until it is bound to a waypoint.
	WaypointMissing ConditionType = "istio.io/WaypointMissing"

	NoWaypointForWildcardService string = "NoWaypointForWildcardService"
)

type ConditionSet = map[ConditionType]*Condition