Change:
It looks like the openapi is not routed properly to set-up the apiservice so apply requests will fail because the fieldmanager is not set-up properly. /cc /sig api-machinery /priority important-soon /kind bug
/wg apply /cc
OpenAPIModels is set to nil for the kube-aggregator server config (which serves the APIServices API): This is done because the kube-aggregator has a special openapi handler that aggregates all the other server's openapi docs. The field controls (at least) two things: /openapi endpoint serving (which we want kube-aggregator to continue to customize) creation of the field manager (which we want kube-aggregator to behave consistently on) We need to decouple presence of OpenAPIConfig and construction of StaticOpenAPISpec (which is needed by the field manager) from construction/installation of OpenAPIVersionedService. That might be a little tricky to untangle, since construction of StaticOpenAPISpec includes paths/operations. The field manager only needs the gvk/schemas.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/lifecycle frozen This is not something we want closed by accident.
/assign
For reference:
Additional lines for reference: This is roughly how SSA consumes the openapi spec. openapi spec -openapi proto model -typeconverter -SSA field manager For built in types, openapi spec -openapi model openapi model -typeconverter A similar thing happens for CRDs As liggitt mentioned, SSA only requires a subset of the information in the openapi generation, and the openapi generation in the aggregator slightly different than the process for builtins and CRDs.
/unassign
/assign

Discussion:
func SetObjectDefaults_Service(in *v1.Service) { SetDefaults_Service(in) <ins> for i := range in.Spec.Ports { a := &in.Spec.Ports[i] if a.Protocol == "" { a.Protocol = "TCP" } } </ins> } func SetObjectDefaults_ServiceList(in *v1.ServiceList) {

// The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". // Default is TCP. <ins> // +default="TCP" </ins> // +optional optional string protocol = 2;

// The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". // Default is TCP. <ins> // +default="TCP" </ins> // +optional Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,2,opt,name=protocol,casttype=Protocol"`

// NewWithDelegate returns a new instance of APIAggregator from the given config. func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.DelegationTarget) (*APIAggregator, error) { <del> // Prevent generic API server to install OpenAPI handler. Aggregator server // has its own customized OpenAPI handler. openAPIConfig := c.GenericConfig.OpenAPIConfig c.GenericConfig.OpenAPIConfig = nil </del> genericServer, err := c.GenericConfig.New("kube-aggregator", delegationTarget) if err != nil { return nil, err

lister:                     informerFactory.Apiregistration().V1().APIServices().Lister(), APIRegistrationInformers:   informerFactory, serviceResolver:            c.ExtraConfig.ServiceResolver, <del> openAPIConfig:              openAPIConfig, </del> <ins> openAPIConfig:              c.GenericConfig.OpenAPIConfig, </ins> egressSelector:             c.GenericConfig.EgressSelector, proxyCurrentCertKeyContent: func() (bytes []byte, bytes2 []byte) { return nil, nil }, }

gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"):     `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`, } <del> const statusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"true"}]}}` // DO NOT ADD TO THIS LIST. // This list is used to ignore known bugs. We shouldn't introduce new bugs. var ignoreList = map[schema.GroupVersionResource]struct{}{ // TODO(#89264): apiservices doesn't work because the openapi is not routed properly. gvr("apiregistration.k8s.io", "v1beta1", "apiservices"): {}, gvr("apiregistration.k8s.io", "v1", "apiservices"):      {}, } </del> <ins> const statusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"True"}]}}` </ins> // Some status-only APIs have empty object on creation. Therefore we don't expect create_test // managedFields for these APIs

t.Fatal(err) } t.Run(mapping.Resource.String(), func(t *testing.T) { <del> if _, ok := ignoreList[mapping.Resource]; ok { t.Skip() } </del> status, ok := statusData[mapping.Resource] if !ok { status = statusDefault

namespace = "" } name := newObj.GetName() <ins> // etcd test stub data doesn't contain apiVersion/kind (!), but apply requires it newObj.SetGroupVersionKind(mapping.GroupVersionKind) createData, err := json.Marshal(newObj.Object) if err != nil { t.Fatal(err) } </ins> rsc := dynamicClient.Resource(mapping.Resource).Namespace(namespace) <del> _, err := rsc.Create(context.TODO(), &newObj, metav1.CreateOptions{FieldManager: "create_test"}) </del> <ins> // apply to create _, err = rsc.Patch(context.TODO(), name, types.ApplyPatchType, []byte(createData), metav1.PatchOptions{FieldManager: "create_test"}) </ins> if err != nil { t.Fatal(err) }