fabric8io / kubernetes-client

Java client for Kubernetes & OpenShift
http://fabric8.io
Apache License 2.0
3.42k stars 1.46k forks source link

Fail when scaling up DeploymentConfig on OpenshiftMockServer #5110

Closed claudio4j closed 1 year ago

claudio4j commented 1 year ago

Describe the bug

I have updated kubernetes-client from 4.13.3. to 5.12.4 and our tests are failing, which I provide a reproducer.

Error

io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://localhost:39453/apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1. Message: Not Found.
        at io.fabric8.openshift.client.server.mock.DeploymentConfigTest.testScale(DeploymentConfigTest.java:199)

Stacktrace

io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: [https://localhost:48887/apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1. Message: Not Found](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html).
 at io.fabric8.kubernetes.client.dsl.base.OperationSupport.requestFailure([OperationSupport.java:684](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.OperationSupport.requestFailure([OperationSupport.java:664](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.OperationSupport.assertResponseCode([OperationSupport.java:615](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse([OperationSupport.java:558](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse([OperationSupport.java:521](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleGet([OperationSupport.java:490](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleGet([OperationSupport.java:460](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.BaseOperation.handleGet([BaseOperation.java:698](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.BaseOperation.getMandatory([BaseOperation.java:184](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation.accept([HasMetadataOperation.java:84](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.openshift.client.dsl.internal.apps.DeploymentConfigOperationsImpl.accept([DeploymentConfigOperationsImpl.java:92](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.openshift.client.dsl.internal.apps.DeploymentConfigOperationsImpl.accept([DeploymentConfigOperationsImpl.java:56](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.openshift.client.dsl.internal.apps.DeploymentConfigOperationsImpl.scale([DeploymentConfigOperationsImpl.java:139](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.openshift.client.dsl.internal.apps.DeploymentConfigOperationsImpl.scale([DeploymentConfigOperationsImpl.java:56](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at io.fabric8.openshift.client.server.mock.DeploymentConfigTest.testScale([DeploymentConfigTest.java:199](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.ArrayList.forEach([ArrayList.java:1540](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))
 at java.base/java.util.ArrayList.forEach([ArrayList.java:1540](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html))

Fabric8 Kubernetes Client version

5.12.4

Steps to reproduce

Add the following test to kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/DeploymentConfigTest.java

@Test
void testScale() {
  DeploymentConfigBuilder dcb = getDeploymentConfig();

  server.expect().withPath("/apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1").andReturn(200, dcb.build()).once();

  DeploymentConfig buildConfig = client.deploymentConfigs().withName("dc1").get();
  assertNotNull(buildConfig);
  assertEquals("dc1", buildConfig.getMetadata().getName());

  // FAIL when the following line is called
  DeploymentConfig dc = client.deploymentConfigs().withName("dc1").scale(1, true);
  assertNotNull(dc.getStatus());
  assertNotNull(dc.getStatus().getLatestVersion());
}

Expected behavior

The scale method should run with no errors.

Runtime

other (please specify in additional context)

Kubernetes API Server version

1.25.3@latest

Environment

Linux

Fabric8 Kubernetes Client Logs

No response

Additional context

No response

shawkins commented 1 year ago

According to the error message there is another request to retrieve the deploymentconfig, so you need to update the number of expectations from once to twice, or use always. There is some implementation difference between the versions - and it has changed again in 6.6, which will more broadly use the scale subresource.

claudio4j commented 1 year ago

Hi Steven, I tried to set always but didn't work, see the full junit report

[INFO] Running io.fabric8.openshift.client.server.mock.DeploymentConfigTest
May 09, 2023 11:41:30 AM okhttp3.mockwebserver.MockWebServer$2 execute
INFO: MockWebServer[60725] starting to accept connections
May 09, 2023 11:41:30 AM okhttp3.mockwebserver.MockWebServer$2 execute
INFO: MockWebServer[60875] starting to accept connections
May 09, 2023 11:41:30 AM okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[60875] received request: GET /apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1 HTTP/1.1 and responded: HTTP/1.1 200 OK
May 09, 2023 11:41:31 AM okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[60875] received request: GET /apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1 HTTP/1.1 and responded: HTTP/1.1 200 OK
May 09, 2023 11:41:31 AM okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[60875] received request: PATCH /apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1 HTTP/1.1 and responded: HTTP/1.1 200 OK
May 09, 2023 11:41:31 AM okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[60875] received request: GET /apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs?fieldSelector=metadata.name%3Ddc1 HTTP/1.1 and responded: HTTP/1.1 404 Client Error
May 09, 2023 11:41:31 AM okhttp3.mockwebserver.MockWebServer$2 acceptConnections
INFO: MockWebServer[60875] done accepting connections: Socket closed
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.324 s <<< FAILURE! - in io.fabric8.openshift.client.server.mock.DeploymentConfigTest
[ERROR] io.fabric8.openshift.client.server.mock.DeploymentConfigTest.testScale  Time elapsed: 0.603 s  <<< ERROR!
io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://localhost:60875/apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs?fieldSelector=metadata.name%3Ddc1. Message: Not Found.
        at io.fabric8.openshift.client.server.mock.DeploymentConfigTest.testScale(DeploymentConfigTest.java:199)

I see the only example that uses .scale(int, boolean) is in ReplicationControllerTest, do you know if the .scale(int) is supposed to work on a DeploymentConfig ?

Also, our production code that uses the DeploymentConfig.scale(int, boolean) just works on a real openshift cluster, but when I updated the fabric8 kubernetes-client from 4.13.3 to 5.10.4 only this test for OpenshiftMockServer failed.

We have to use kubernetes-client 5.10.2, but for this test case scenario I used 5.12.4, which failed for the same reason.

claudio4j commented 1 year ago

Does this call using the fieldSelector should work on OpenshiftMockServer ? Just asking because I am not familiar with OpenshiftMockServer and I am trying to understand.

received request: GET /apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs?fieldSelector=metadata.name%3Ddc1 HTTP/1.1 and responded: HTTP/1.1 404 Client Error

Sorry asking this questins here, but I could not find a chat or mailing list for kubernetes-client, is there one ?

shawkins commented 1 year ago

Does this call using the fieldSelector should work on OpenshiftMockServer ?

You need a new expectation if the url is different.

Just asking because I am not familiar with OpenshiftMockServer and I am trying to understand.

There's nothing really special about it. It's still just a mock server. If it's running in crud mode it may be able to answer a lot of interactions on its own. If it's not in crud mode, then you need an expectation for everything. I'm guessing here that you are in non-crud mode.

Sorry asking this questins here, but I could not find a chat or mailing list for kubernetes-client, is there one ?

I'm not sure what the most actively monitored chat is to be honest.

claudio4j commented 1 year ago

I was able to make .scale(1, true) work

@Test
void testScale() {
  String dcName = "dc1";
  DeploymentConfig dcb = new DeploymentConfigBuilder()
    .editOrNewMetadata()
        .withName(dcName)
        .withGeneration(Long.valueOf(1))
    .endMetadata()
    .editOrNewSpec()
      .withReplicas(1)
      .editOrNewTemplate()
          .editOrNewSpec()
              .withContainers(new ContainerBuilder()
                  .withImage("image")
                  .withName(dcName)
                  .build())
          .endSpec()
      .endTemplate()
    .endSpec()
    .withNewStatus()
      .withReplicas(0)
      .withLatestVersion(Long.valueOf(1))
      .withObservedGeneration(Long.valueOf(1))
    .endStatus()
    .build();

  DeploymentConfig dcbScaled = new DeploymentConfigBuilder()
    .editOrNewMetadata()
        .withName(dcName)
        .withGeneration(Long.valueOf(1))
    .endMetadata()
    .editOrNewSpec()
      .withReplicas(1)
      .editOrNewTemplate()
          .editOrNewSpec()
              .withContainers(new ContainerBuilder()
                  .withImage("image")
                  .withName(dcName)
                  .build())
          .endSpec()
      .endTemplate()
    .endSpec()
    .withNewStatus()
      .withReplicas(1)
      .withLatestVersion(Long.valueOf(1))
      .withObservedGeneration(Long.valueOf(1))
    .endStatus()
    .build();

  server.expect().withPath("/apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1").andReturn(200, dcb).always();
  server.expect().withPath("/apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs/dc1").andReturn(200, dcbScaled).once();

  server.expect()
    .withPath("/apis/apps.openshift.io/v1/namespaces/test/deploymentconfigs?fieldSelector=metadata.name%3Ddc1")
    .andReturn(200,
      new DeploymentConfigListBuilder().withItems(dcbScaled).withMetadata(new ListMetaBuilder().build()).build())
    .always();

  DeploymentConfig dc2 = client.deploymentConfigs().withName("dc1").scale(1, true);
  assertNotNull(dc2.getStatus());
  assertNotNull(dc2.getStatus().getLatestVersion());
}

Thank you Steven