hashicorp / consul

Consul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure.
https://www.consul.io
Other
28.46k stars 4.43k forks source link

/v1/catalog/register endpoint returning Request decode failed: json: cannot unmarshal array #8815

Open myugan opened 4 years ago

myugan commented 4 years ago

Overview of the Issue

Services successfully register with consul command, but it's shown an error when register via HTTP API.

Reproduction Steps

Steps to reproduce this issue, eg:

  1. Create JSON file to register service for example redis.json:
    {
     "service" : [{
       "id": "redis",
       "name": "redis",
       "address": "127.0.0.1"
     }]
    }
  2. Register via consul command: consul services register tes.json
  3. Also register the service via HTTP API: curl -XPUT --data @redis.json http://127.0.0.1:8500/v1/catalog/register

    Consul info for both Client and Server

Client info ``` agent: check_monitors = 0 check_ttls = 0 checks = 0 services = 1 build: prerelease = revision = 3111cb8c version = 1.8.0 consul: acl = disabled bootstrap = true known_datacenters = 1 leader = true leader_addr = 161.35.14.119:8300 server = true raft: applied_index = 1104 commit_index = 1104 fsm_pending = 0 last_contact = 0 last_log_index = 1104 last_log_term = 4 last_snapshot_index = 0 last_snapshot_term = 0 latest_configuration = [{Suffrage:Voter ID:1910c298-4535-38cc-bddd-d075c8ea9985 Address:161.35.14.119:8300}] latest_configuration_index = 0 num_peers = 0 protocol_version = 3 protocol_version_max = 3 protocol_version_min = 0 snapshot_version_max = 1 snapshot_version_min = 0 state = Leader term = 4 runtime: arch = amd64 cpu_count = 4 goroutines = 101 max_procs = 4 os = linux version = go1.14.4 serf_lan: coordinate_resets = 0 encrypted = false event_queue = 1 event_time = 4 failed = 0 health_score = 0 intent_queue = 0 left = 0 member_time = 1 members = 1 query_queue = 0 query_time = 1 serf_wan: coordinate_resets = 0 encrypted = false event_queue = 0 event_time = 1 failed = 0 health_score = 0 intent_queue = 0 left = 0 member_time = 1 members = 1 query_queue = 0 query_time = 1 ```
Server info ``` agent: check_monitors = 0 check_ttls = 0 checks = 0 services = 1 build: prerelease = revision = 3111cb8c version = 1.8.0 consul: acl = disabled bootstrap = true known_datacenters = 1 leader = true leader_addr = 161.35.14.119:8300 server = true raft: applied_index = 1104 commit_index = 1104 fsm_pending = 0 last_contact = 0 last_log_index = 1104 last_log_term = 4 last_snapshot_index = 0 last_snapshot_term = 0 latest_configuration = [{Suffrage:Voter ID:1910c298-4535-38cc-bddd-d075c8ea9985 Address:161.35.14.119:8300}] latest_configuration_index = 0 num_peers = 0 protocol_version = 3 protocol_version_max = 3 protocol_version_min = 0 snapshot_version_max = 1 snapshot_version_min = 0 state = Leader term = 4 runtime: arch = amd64 cpu_count = 4 goroutines = 101 max_procs = 4 os = linux version = go1.14.4 serf_lan: coordinate_resets = 0 encrypted = false event_queue = 1 event_time = 4 failed = 0 health_score = 0 intent_queue = 0 left = 0 member_time = 1 members = 1 query_queue = 0 query_time = 1 serf_wan: coordinate_resets = 0 encrypted = false event_queue = 0 event_time = 1 failed = 0 health_score = 0 intent_queue = 0 left = 0 member_time = 1 members = 1 query_queue = 0 query_time = 1 ```

Operating system and Environment details

Consul: 1.8.0 OS: Ubuntu 18.04 LTS

Log Fragments

Include appropriate Client or Server log fragments. If the log is longer than a few dozen lines, please include the URL to the gist of the log instead of posting it in the issue. Use -log-level=TRACE on the client and server to capture the maximum log detail.

jsosulska commented 4 years ago

Hi @myugan

Welcome to Consul, and thanks for posting. I ran through this on 1.8.4 and 1.7.7 and confirm what you saw. The error can be seen below:

> curl -XPUT --data @services.json http://127.0.0.1:8500/v1/catalog/register
Request decode failed: json: cannot unmarshal array into Go struct field RegisterRequest.Service of type structs.NodeService

The issue is because you have the service stanza encapsulated with [, and ]. This tells the system that the service block should expect an array. Service does not take an array, as each registration should be a single instance of the service. To get rid of the error, simply remove the [ ... ] brackets.

jsosulska commented 4 years ago

We could, however, provide stronger validation from our CLI that the services are valid.

jsosulska commented 4 years ago

So, after digging into this more, I think I found where the validation falls apart.

When the CLI command is ran, the endpoint it is using under the hood is the agent/service. When you use the catalog register endpoint, that validation comes through. We could look at porting that logic to the Agent API.

oxycash commented 1 year ago

I have a similar issue.

My service.json

{
    "Name": "postgres-cluster",
    "Id": "postgres-cluster-master",
    "Port": 6432,
    "Check": [
      {"http": "http://ipaddress/master", "Interval": "2s"}, {"Args": ["systemctl", "status", "pgbouncer"], "Interval": "5s"}
    ],
    "Tags": ["master"]
  }

Error

curl -XPUT --data @service_postgres-cluster-master.json  http://127.0.0.1:8500/v1/agent/service/register
Request decode failed: json: cannot unmarshal array into Go struct field .Check of type struct { Interval interface {}; Timeout interface {}; TTL interface {}; DeregisterCriticalServiceAfter interface {}; Args []string "json:\"args\""; ScriptArgsSnake []string "json:\"script_args\""; DeregisterCriticalServiceAfterSnake interface {} "json:\"deregister_critical_service_after\""; DockerContainerIDSnake string "json:\"docker_container_id\""; TLSServerNameSnake string "json:\"tls_server_name\""; TLSSkipVerifySnake bool "json:\"tls_skip_verify\""; GRPCUseTLSSnake bool "json:\"grpc_use_tls\""; H2PingUseTLSSnake bool "json:\"h2ping_use_tls\""; ServiceID string "json:\"ServiceID\""; ServiceIDSnake string "json:\"service_id\""; *structs.Alias }
blake commented 1 year ago

@oxycash The Check parameter only allows configuring a single health check definition. The value of the Check field should be JSON dictionary.

From your service config, it seems you're trying to define multiple health checks for this service. You can do that using the Checks (plural) parameter.

{
    "Name": "postgres-cluster",
    "Id": "postgres-cluster-master",
    "Port": 6432,
    "Checks": [
      {
        "http": "http://ipaddress/master",
        "Interval": "2s"
      },
      {
        "Args": ["systemctl", "status", "pgbouncer"],
        "Interval": "5s"
      }
    ],
    "Tags": ["master"]
  }
oxycash commented 1 year ago
curl -XPUT --data @service_postgres-cluster-master.json http://127.0.0.1:8500/v1/catalog/register
Request decode failed: json: unknown field "Name"
oxycash commented 1 year ago

The same worked after I tried to register via agent/service/register

blake commented 1 year ago

@oxycash The /catalog/register API takes a different request payload than /agent/services/register. A sample payload is documented here. https://developer.hashicorp.com/consul/api-docs/catalog#sample-payload

oxycash commented 1 year ago

image

I thought consul services register and this API uses same payload but I am getting this error.

https://developer.hashicorp.com/consul/commands/services/register https://developer.hashicorp.com/consul/api-docs/agent/service#register-service

I am currently using consul 1.15

Edit: Added Service in the payload. now the error is TTL check

400 (Invalid check: TTL must be > 0 for TTL checks

But I have an HTTP check