mesosphere / marathon

Deploy and manage containers (including Docker) on top of Apache Mesos at scale.
https://mesosphere.github.io/marathon/
Apache License 2.0
4.07k stars 845 forks source link

requirement failed: IP address and ports are not allowed at the same time #5171

Closed greenpau closed 7 years ago

greenpau commented 7 years ago

Submitting the following JSON via PUT /v2/apps API call.

{
  "id": "/iperf/iperf-server-host1-5201",
  "constraints": [ [ "hostname", "CLUSTER", "host1" ] ],
  "cmd": "iperf3 -s -p 5201 --json",
  "cpus": 1,
  "mem": 512,
  "disk": 0,
  "instances": 1,
  "container": {
    "type": "DOCKER",
    "volumes": [],
    "docker": {
      "image": "networkstatic/iperf3:latest",
      "network": "USER",
      "portMappings": [
        { "containerPort": 5201, "servicePort": 5201, "protocol": "tcp", "labels": {} }
      ],
      "privileged": false,
      "parameters": [
        { "key": "hostname", "value": "iperf-host1-5201.iperf.marathon.mesos" }
      ],
      "forcePullImage": true
    }
  },
  "labels": {
    "IPERF_FUNCTION": "SERVER"
  },
  "ipAddress": {
    "networkName": "Lab""
  }
}

Receiving the following error:

"requirement failed: IP address (Some(IpAddress(List(),Map(),DiscoveryInfo(List()),Some(Lab)))) and ports (List(PortDefinition(0,tcp,None,Map()))) are not allowed at the same time"

The error is triggered by the following code: https://github.com/mesosphere/marathon/blob/master/src/main/scala/mesosphere/marathon/state/AppDefinition.scala#L90-L92

greenpau commented 7 years ago

Importantly, when I paste the payload via web UI (i.e. Create Application) it works, but when using API it fails with the above error.

greenpau commented 7 years ago

Adding ports did not help

    "docker": {
      "image": "networkstatic/iperf3:latest",
      "network": "USER",
      "ports": [
        5201
      ],

Adding portDefinitions did not help:

    "docker": {
      "image": "networkstatic/iperf3:latest",
      "network": "USER",
      "portDefinitions": [
        { "port": 5201 }
      ],
jdef commented 7 years ago

I see that you're using PUT. Are you updating an existing app?

PUT actually has "patch" semantics by default. It's unfortunate, and we'll be addressing this for Marathon 1.5. We just released 1.4.0-RC8 which allows you to specify partialUpdate=false as a query parameter for app updates via PUT -- this disables the "patch" semantic and does a wholesale replacement of an existing app. (This change will be forward-ported to master soon).

Here's why "patch" semantics fail when using USER networking for your JSON: "portDefinitions" is not defined in your original JSON at all, so Marathon will automatically inject a "portDefinitions": [ { "port": 0 } ] into your app definition. Boom, it's now an invalid JSON because it has both portDefinitions and portMappings.

Workaround is to define "portDefinitions": [] in the JSON that you originally posted. This says "Marathon, don't give me a default port-definition". Or if you want to use 1.4.0-RC8 you can add the partialUpdate=false query param for your PUT

On Mon, Feb 13, 2017 at 11:45 AM, Paul Greenberg notifications@github.com wrote:

Adding ports did not help

"docker": {
  "image": "networkstatic/iperf3:latest",
  "network": "USER",
  "ports": [
    5201
  ],

Adding portDefinitions did not help:

"docker": {
  "image": "networkstatic/iperf3:latest",
  "network": "USER",
  "portDefinitions": [
    { "port": 5201 }
  ],

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mesosphere/marathon/issues/5171#issuecomment-279448660, or mute the thread https://github.com/notifications/unsubscribe-auth/ACPVLGnCbaEqCXanLesEsh5Eo7fxflLVks5rcIjHgaJpZM4L_Z7E .

greenpau commented 7 years ago

Here's why "patch" semantics fail when using USER networking for your JSON: "portDefinitions" is not defined in your original JSON at all, so Marathon will automatically inject a "portDefinitions": [ { "port": 0 } ] into your app definition. Boom, it's now an invalid JSON because it has both portDefinitions and portMappings.

:+1: thank you for the explanation. I switched to POST.

define "portDefinitions": [] in the JSON

:1st_place_medal: gotcha!