无法使用 kubernetes python 客户端创建 CRD

Unable to create CRD using kubernetes python client

发生了什么

我正在尝试使用 kubernetes python 客户端在 kubernetes 中创建自定义资源定义,但我无法这样做,如果有人可以在这里解释我做错了什么,那将会很有帮助

Traceback (most recent call last):
  File "/home/talha/python/examples/custom_object.py", line 239, in <module>
    main()
  File "/home/talha/python/examples/custom_object.py", line 191, in main
    api.create_custom_resource_definition(body=crd)
  File "/home/talha/python/kubernetes/client/api/apiextensions_v1beta1_api.py", line 65, in create_custom_resource_definition
    return self.create_custom_resource_definition_with_http_info(body, **kwargs)  # noqa: E501
  File "/home/talha/python/kubernetes/client/api/apiextensions_v1beta1_api.py", line 166, in create_custom_resource_definition_with_http_info
    collection_formats=collection_formats)
  File "/home/talha/python/kubernetes/client/api_client.py", line 353, in call_api
    _preload_content, _request_timeout, _host)
  File "/home/talha/python/kubernetes/client/api_client.py", line 184, in __call_api
    _request_timeout=_request_timeout)
  File "/home/talha/python/kubernetes/client/api_client.py", line 397, in request
    body=body)
  File "/home/talha/python/kubernetes/client/rest.py", line 280, in POST
    body=body)
  File "/home/talha/python/kubernetes/client/rest.py", line 233, in request
    raise ApiException(http_resp=r)
kubernetes.client.exceptions.ApiException: (400)
Reason: Bad Request
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'Date': 'Mon, 31 Aug 2020 09:51:19 GMT', 'Content-Length': '610'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"CustomResourceDefinition in version \"v1beta1\" cannot be handled as a CustomResourceDefinition: v1beta1.CustomResourceDefinition.ObjectMeta: v1.ObjectMeta.Labels: CreationTimestamp: unmarshalerDecoder: parsing time \"null\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \"null\" as \"2006\", error found in #10 byte of ...|p\": \"null\", \"labels\"|..., bigger context ...|o/version\": \"v0.2.4\"}, \"creationTimestamp\": \"null\", \"labels\": {\"component\": \"velero\"}, \"name\": \"back|...","reason":"BadRequest","code":400}

你预期会发生什么: 创建 CRD

如何重现它(尽可能精简):

    config.load_kube_config()
    api = client.ApiextensionsV1beta1Api()
    crd = {
         "apiVersion":"apiextensions.k8s.io/v1beta1",
         "kind":"CustomResourceDefinition",
         "metadata":{
            "annotations":{
               "controller-gen.kubebuilder.io/version":"v0.2.4"
            },
            "creationTimestamp":"null",
            "labels":{
               "component":"velero"
            },
            "name":"backupstoragelocations.velero.io"
         },
         "spec":{
            "group":"velero.io",
            "names":{
               "kind":"BackupStorageLocation",
               "listKind":"BackupStorageLocationList",
               "plural":"backupstoragelocations",
               "singular":"backupstoragelocation"
            },
            "preserveUnknownFields":"false",
            "scope":"Namespaced",
            "validation":{
               "openAPIV3Schema":{
                  "description":"BackupStorageLocation is a location where Velero stores backup objects.",
                  "properties":{
                     "apiVersion":{
                        "description":"APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
                        "type":"string"
                     },
                     "kind":{
                        "description":"Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
                        "type":"string"
                     },
                     "metadata":{
                        "type":"object"
                     },
                     "spec":{
                        "description":"BackupStorageLocationSpec defines the specification for a Velero BackupStorageLocation.",
                        "properties":{
                           "accessMode":{
                              "description":"AccessMode defines the permissions for the backup storage location.",
                              "enum":[
                                 "ReadOnly",
                                 "ReadWrite"
                              ],
                              "type":"string"
                           },
                           "backupSyncPeriod":{
                              "description":"BackupSyncPeriod defines how frequently to sync backup API objects from object storage. A value of 0 disables sync.",
                              "nullable":"true",
                              "type":"string"
                           },
                           "config":{
                              "additionalProperties":{
                                 "type":"string"
                              },
                              "description":"Config is for provider-specific configuration fields.",
                              "type":"object"
                           },
                           "objectStorage":{
                              "description":"ObjectStorageLocation specifies the settings necessary to connect to a provider's object storage.",
                              "properties":{
                                 "bucket":{
                                    "description":"Bucket is the bucket to use for object storage.",
                                    "type":"string"
                                 },
                                 "caCert":{
                                    "description":"CACert defines a CA bundle to use when verifying TLS connections to the provider.",
                                    "format":"byte",
                                    "type":"string"
                                 },
                                 "prefix":{
                                    "description":"Prefix is the path inside a bucket to use for Velero storage. Optional.",
                                    "type":"string"
                                 }
                              },
                              "required":[
                                 "bucket"
                              ],
                              "type":"object"
                           },
                           "provider":{
                              "description":"Provider is the provider of the backup storage.",
                              "type":"string"
                           }
                        },
                        "required":[
                           "objectStorage",
                           "provider"
                        ],
                        "type":"object"
                     },
                     "status":{
                        "description":"BackupStorageLocationStatus describes the current status of a Velero BackupStorageLocation.",
                        "properties":{
                           "accessMode":{
                              "description":"AccessMode is an unused field. \n Deprecated: there is now an AccessMode field on the Spec and this field will be removed entirely as of v2.0.",
                              "enum":[
                                 "ReadOnly",
                                 "ReadWrite"
                              ],
                              "type":"string"
                           },
                           "lastSyncedRevision":{
                              "description":"LastSyncedRevision is the value of the `metadata/revision` file in the backup storage location the last time the BSL's contents were synced into the cluster. \n Deprecated: this field is no longer updated or used for detecting changes to the location's contents and will be removed entirely in v2.0.",
                              "type":"string"
                           },
                           "lastSyncedTime":{
                              "description":"LastSyncedTime is the last time the contents of the location were synced into the cluster.",
                              "format":"date-time",
                              "nullable":"true",
                              "type":"string"
                           },
                           "phase":{
                              "description":"Phase is the current state of the BackupStorageLocation.",
                              "enum":[
                                 "Available",
                                 "Unavailable"
                              ],
                              "type":"string"
                           }
                        },
                        "type":"object"
                     }
                  },
                  "type":"object"
               }
            },
            "version":"v1",
            "versions":[
               {
                  "name":"v1",
                  "served":"true",
                  "storage":"true"
               }
            ]
         }
      }
    api.create_custom_resource_definition(body=crd)

还有什么我们需要知道的吗?:

环境:

我们来看看报错信息:

CustomResourceDefinition in version "v1beta1" cannot be handled as a CustomResourceDefinition: v1beta1.CustomResourceDefinition.ObjectMeta: v1.ObjectMeta.Labels: CreationTimestamp: unmarshalerDecoder: parsing time "null" as "2006-01-02T15:04:05Z07:00": cannot parse "null" as "2006"

因此,如错误消息所示,CreationTimeStamp 存在问题。现在的问题是,你的 CreationTimestamp 怎么了?

您的创建时间戳应该是:

{
"creationTimestamp":null, // creationTimestamp is actually defined, but the value is null
}

而不是:

{
"creationTimestamp":"null", // setting creationTimestamp equal to a string value "null"
}