1/*
2Copyright 2018 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package client
18
19import (
20	"context"
21
22	apierrors "k8s.io/apimachinery/pkg/api/errors"
23
24	"k8s.io/apimachinery/pkg/api/meta"
25	"k8s.io/apimachinery/pkg/runtime"
26	"k8s.io/apimachinery/pkg/types"
27)
28
29// ObjectKey identifies a Kubernetes Object.
30type ObjectKey = types.NamespacedName
31
32// ObjectKeyFromObject returns the ObjectKey given a runtime.Object
33func ObjectKeyFromObject(obj runtime.Object) (ObjectKey, error) {
34	accessor, err := meta.Accessor(obj)
35	if err != nil {
36		return ObjectKey{}, err
37	}
38	return ObjectKey{Namespace: accessor.GetNamespace(), Name: accessor.GetName()}, nil
39}
40
41// Patch is a patch that can be applied to a Kubernetes object.
42type Patch interface {
43	// Type is the PatchType of the patch.
44	Type() types.PatchType
45	// Data is the raw data representing the patch.
46	Data(obj runtime.Object) ([]byte, error)
47}
48
49// TODO(directxman12): is there a sane way to deal with get/delete options?
50
51// Reader knows how to read and list Kubernetes objects.
52type Reader interface {
53	// Get retrieves an obj for the given object key from the Kubernetes Cluster.
54	// obj must be a struct pointer so that obj can be updated with the response
55	// returned by the Server.
56	Get(ctx context.Context, key ObjectKey, obj runtime.Object) error
57
58	// List retrieves list of objects for a given namespace and list options. On a
59	// successful call, Items field in the list will be populated with the
60	// result returned from the server.
61	List(ctx context.Context, list runtime.Object, opts ...ListOption) error
62}
63
64// Writer knows how to create, delete, and update Kubernetes objects.
65type Writer interface {
66	// Create saves the object obj in the Kubernetes cluster.
67	Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error
68
69	// Delete deletes the given obj from Kubernetes cluster.
70	Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error
71
72	// Update updates the given obj in the Kubernetes cluster. obj must be a
73	// struct pointer so that obj can be updated with the content returned by the Server.
74	Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error
75
76	// Patch patches the given obj in the Kubernetes cluster. obj must be a
77	// struct pointer so that obj can be updated with the content returned by the Server.
78	Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error
79
80	// DeleteAllOf deletes all objects of the given type matching the given options.
81	DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error
82}
83
84// StatusClient knows how to create a client which can update status subresource
85// for kubernetes objects.
86type StatusClient interface {
87	Status() StatusWriter
88}
89
90// StatusWriter knows how to update status subresource of a Kubernetes object.
91type StatusWriter interface {
92	// Update updates the fields corresponding to the status subresource for the
93	// given obj. obj must be a struct pointer so that obj can be updated
94	// with the content returned by the Server.
95	Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error
96
97	// Patch patches the given object's subresource. obj must be a struct
98	// pointer so that obj can be updated with the content returned by the
99	// Server.
100	Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error
101}
102
103// Client knows how to perform CRUD operations on Kubernetes objects.
104type Client interface {
105	Reader
106	Writer
107	StatusClient
108}
109
110// IndexerFunc knows how to take an object and turn it into a series
111// of non-namespaced keys. Namespaced objects are automatically given
112// namespaced and non-spaced variants, so keys do not need to include namespace.
113type IndexerFunc func(runtime.Object) []string
114
115// FieldIndexer knows how to index over a particular "field" such that it
116// can later be used by a field selector.
117type FieldIndexer interface {
118	// IndexFields adds an index with the given field name on the given object type
119	// by using the given function to extract the value for that field.  If you want
120	// compatibility with the Kubernetes API server, only return one key, and only use
121	// fields that the API server supports.  Otherwise, you can return multiple keys,
122	// and "equality" in the field selector means that at least one key matches the value.
123	// The FieldIndexer will automatically take care of indexing over namespace
124	// and supporting efficient all-namespace queries.
125	IndexField(ctx context.Context, obj runtime.Object, field string, extractValue IndexerFunc) error
126}
127
128// IgnoreNotFound returns nil on NotFound errors.
129// All other values that are not NotFound errors or nil are returned unmodified.
130func IgnoreNotFound(err error) error {
131	if apierrors.IsNotFound(err) {
132		return nil
133	}
134	return err
135}
136