I only get one CID, why do I get **multiple** CIDs?

Hi, I have installed ipfs clister in kebernetes.
I have uploaded an image with REST Api /aa call. I get this as response:

response: {"name":"","cid":"QmQGYxCYyuRgkBwf3mzE9cstfRCXzkeL6HDv1ENF5CbRUB","size":13,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmWCHpu8gM2y6AUAa7jmsPKjSBReqPD9ykpXh6t6WCXptB","size":25,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"6ed9e6ca24df38be0b54d3d00","cid":"QmeJRJqjWzdhUfwRJWCpvg9i1scbtBifqTukcS76jgyUMn","size":9203,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmcjeQaN5gKA3qAntZPkTUxfbiMswTm6cTtn829SJpXVFQ","size":15,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmQt3wmQ9QDnWMWf1EYXbMQcvArXygJFEgqD9HmfRpbH3s","size":11,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmcNzWmuM8F6nrE8HSQWLjoApjbQhJiYAjiGDotw9oS8t4","size":19,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmNUoXf9j388gnAFEkemnMzXmgDADxWpEriEtQ4hYaVLLD","size":16,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}

I only get one CID, why do I get multiple CIDs?

Hello. Can you explain in more detail where did you obtain this response?

Hi Hector,
I have installed ipfs cluster in kubernetes. Here is my ipfs-cluster.yaml:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ipfs-cluster
  namespace: ipfs-cluster
spec:
  serviceName: ipfs-cluster
  replicas: 3
  selector:
    matchLabels:
      app: ipfs-cluster
  template:
    metadata:
      labels:
        app: ipfs-cluster
    spec:
      initContainers:
        - name: configure-ipfs
          image: "ipfs/kubo:v0.31.0"
          command: ["sh", "/custom/configure-ipfs.sh"]
          volumeMounts:
            - name: ipfs-storage
              mountPath: /data/ipfs
            - name: configure-script
              mountPath: /custom
      containers:
        - name: ipfs
          image: "ipfs/kubo:v0.31.0"
          imagePullPolicy: IfNotPresent
          env:
            - name: IPFS_FD_MAX
              value: "4096"
          ports:
            - name: swarm
              protocol: TCP
              containerPort: 4001
            - name: swarm-udp
              protocol: UDP
              containerPort: 4002
            - name: api
              protocol: TCP
              containerPort: 5001
            - name: ws
              protocol: TCP
              containerPort: 8081
            - name: http
              protocol: TCP
              containerPort: 8080
          livenessProbe:
            tcpSocket:
              port: swarm
            initialDelaySeconds: 30
            timeoutSeconds: 5
            periodSeconds: 15
          volumeMounts:
            - mountPath: /data/ipfs
              name: ipfs-storage
            - name: configure-script
              mountPath: /custom
          resources:
            {}
        - name: ipfs-cluster
          image: "ipfs/ipfs-cluster:latest"
          imagePullPolicy: IfNotPresent
          command: ["sh", "/custom/entrypoint.sh"]
          envFrom:
            - configMapRef:
                name: env-config
          env:
            - name: BOOTSTRAP_PEER_ID
              valueFrom:
                configMapKeyRef:
                  name: env-config
                  key: bootstrap-peer-id
            - name: BOOTSTRAP_PEER_PRIV_KEY
              valueFrom:
                secretKeyRef:
                  name: secret-config
                  key: bootstrap-peer-priv-key
            - name: CLUSTER_SECRET
              valueFrom:
                secretKeyRef:
                  name: secret-config
                  key: cluster-secret
            - name: CLUSTER_MONITOR_PING_INTERVAL
              value: "3m"
            - name: SVC_NAME
              value: ipfs-cluster
          ports:
            - name: api-http
              containerPort: 9094
              protocol: TCP
            - name: proxy-http
              containerPort: 9095
              protocol: TCP
            - name: cluster-swarm
              containerPort: 9096
              protocol: TCP
          livenessProbe:
            tcpSocket:
              port: cluster-swarm
            initialDelaySeconds: 5
            timeoutSeconds: 5
            periodSeconds: 10
          volumeMounts:
            - name: cluster-storage
              mountPath: /data/ipfs-cluster
            - name: configure-script
              mountPath: /custom
          resources:
            {}

      volumes:
      - name: configure-script
        configMap:
          name: ipfs-cluster-set-bootstrap-conf


  volumeClaimTemplates:
    - metadata:
        name: cluster-storage
      spec:
        storageClassName: local-path
        accessModes: ["ReadWriteOnce"]
        # persistentVolumeReclaimPolicy: Retain
        resources:
          requests:
            storage: 5Gi
    - metadata:
        name: ipfs-storage
      spec:
        storageClassName: local-path
        accessModes: ["ReadWriteOnce"]
        # persistentVolumeReclaimPolicy: Retain
        resources:
          requests:
            storage: 200Gi

In my nextJs app I make an axios call:

         const IPFS_CLUSTER_RESTAPI_URL = http://10.43.90.35:9094;

         // to read the file
        const fileStream = fs.createReadStream(filePath);
        const metadata = {
            name: fields['name'],
            description: fields['description'],
            image: fileStream,
            attributes: [{
                trait_type: "Version",
                value: "1.0"
            }, {
                trait_type: "marketplace",
                value: "ART"
            }],
        };
   
        //Upload NFT to IPFS & Filecoin
        const response = await axios.post(IPFS_CLUSTER_RESTAPI_URL + '/add', metadata, {
            headers: {
                'Content-Type': 'multipart/form-data'
            },
        });

You get multiple CIDs like that when you upload multiple files through a single multipart request to /add. The last one is usually the ā€œrootā€ cid.

I believe that you are uploading the metadata as ā€œform-dataā€ in your POST, and thus making a request with multiple parts.

Cluster-pin metadata in cluster /add endpoint goes as part of the query params to the request (i.e. ?name=myname&meta-description=desc&meta-attributes=a,b,c). Note that metadata field names must be prepended by ā€œmeta-ā€.

See:

Yes, I use the metadata as ā€˜form-dataā€™ in my POST call.
I donā€™t see anything about root-CID, all CID are the same.
How do I get only one CID?

Donā€™t use the metadata as form-data as this is equivalent to adding multiple files, and so you get one CID per file.

ok, that means donā€™t use multipart/form-data.
How do I send the image file?

ohne multipart/form-data bekomme ich einen Fehler:
Anfrage fehlgeschlagen mit Statuscode 400

Itā€™s explained in the docs I sent.

Hi @hector ,
Thank you, now I only get a CID. But I still had to use form-data:

const metadata = JSON.stringify({
            "meta-name": fields['name'],
            "meta-description": fields['description'],
            "meta-file": fs.createReadStream(filePath),
            "meta-attributes": [{
                trait_type: "Version",
                value: "1.0"
            }, {
                trait_type: "marketplace",
                value: "ARTWISTA"
            }],
        });

formData.append("meta-data", metadata);
        //Upload NFT to IPFS & Filecoin
        const response = await axios.post(IPFS_CLUSTER_RESTAPI_URL + '/add', 
            formData, {
            maxBodyLength: Infinity,
            headers: {
              'Content-Type': `multipart/form-data;`,
              // Authorization: `Bearer ${JWT_SECRET_IPFS_CLUSTER}`
            }
          });

One more question, now i want to use IPFS gateway local in kubernetes:

Curl 
http://10.43.90.35:8080/ipfs/QmVmrV76aiVcULqGQfH8kYkQXzhpvtVYy9e7hAQXjt4AaQ

But no answer there. Do you have an idea?

In this case it seems you are uploading a json with embedded binary data, which Iā€™m not sure is the best (should probably base64 it first).

Possibly your gateway is only listening on localhost and you need to change Addresses.Gateway to use 0.0.0.0 .

Thanks @hector ,

  1. yes, a json is uploaded
  2. yes, my service mapped to localhost:
Gateway server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready

These commands in the script do not seem to work:

ipfs config --json Addresses.Gateway /ip4/0.0.0.0/tcp/8080

what script? Where did you find that command?

apiVersion: v1
kind: ConfigMap
metadata:
  name: ipfs-cluster-set-bootstrap-conf
  namespace: ipfs-cluster
data:
  entrypoint.sh: |
    #!/bin/sh
    user=ipfs
    sleep 10
    # This is a custom entrypoint for k8s designed to connect to the bootstrap
    # node running in the cluster. It has been set up using a configmap to
    # allow changes on the fly.


  
..........