mirror of https://github.com/k3s-io/k3s
Merge pull request #995 from csrwng/refactor_api_client
Break up API client into per-resource client and common codepull/6/head
commit
ae0997807e
|
@ -34,28 +34,51 @@ import (
|
||||||
|
|
||||||
// Interface holds the methods for clients of Kubenetes,
|
// Interface holds the methods for clients of Kubenetes,
|
||||||
// an interface to allow mock testing.
|
// an interface to allow mock testing.
|
||||||
// TODO: split this up by resource?
|
|
||||||
// TODO: these should return/take pointers.
|
// TODO: these should return/take pointers.
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
|
PodInterface
|
||||||
|
ReplicationControllerInterface
|
||||||
|
ServiceInterface
|
||||||
|
VersionInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodInterface has methods to work with Pod resources
|
||||||
|
type PodInterface interface {
|
||||||
ListPods(selector labels.Selector) (api.PodList, error)
|
ListPods(selector labels.Selector) (api.PodList, error)
|
||||||
GetPod(name string) (api.Pod, error)
|
GetPod(name string) (api.Pod, error)
|
||||||
DeletePod(name string) error
|
DeletePod(name string) error
|
||||||
CreatePod(api.Pod) (api.Pod, error)
|
CreatePod(api.Pod) (api.Pod, error)
|
||||||
UpdatePod(api.Pod) (api.Pod, error)
|
UpdatePod(api.Pod) (api.Pod, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplicationControllerInterface has methods to work with ReplicationController resources
|
||||||
|
type ReplicationControllerInterface interface {
|
||||||
ListReplicationControllers(selector labels.Selector) (api.ReplicationControllerList, error)
|
ListReplicationControllers(selector labels.Selector) (api.ReplicationControllerList, error)
|
||||||
GetReplicationController(name string) (api.ReplicationController, error)
|
GetReplicationController(name string) (api.ReplicationController, error)
|
||||||
CreateReplicationController(api.ReplicationController) (api.ReplicationController, error)
|
CreateReplicationController(api.ReplicationController) (api.ReplicationController, error)
|
||||||
UpdateReplicationController(api.ReplicationController) (api.ReplicationController, error)
|
UpdateReplicationController(api.ReplicationController) (api.ReplicationController, error)
|
||||||
DeleteReplicationController(string) error
|
DeleteReplicationController(string) error
|
||||||
WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
|
WatchReplicationControllers(label, field labels.Selector, resourceVersion uint64) (watch.Interface, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceInterface has methods to work with Service resources
|
||||||
|
type ServiceInterface interface {
|
||||||
GetService(name string) (api.Service, error)
|
GetService(name string) (api.Service, error)
|
||||||
CreateService(api.Service) (api.Service, error)
|
CreateService(api.Service) (api.Service, error)
|
||||||
UpdateService(api.Service) (api.Service, error)
|
UpdateService(api.Service) (api.Service, error)
|
||||||
DeleteService(string) error
|
DeleteService(string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VersionInterface has a method to retrieve the server version
|
||||||
|
type VersionInterface interface {
|
||||||
|
ServerVersion() (*version.Info, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client is the actual implementation of a Kubernetes client.
|
||||||
|
type Client struct {
|
||||||
|
*RESTClient
|
||||||
|
}
|
||||||
|
|
||||||
// StatusErr might get returned from an api call if your request is still being processed
|
// StatusErr might get returned from an api call if your request is still being processed
|
||||||
// and hence the expected return data is not available yet.
|
// and hence the expected return data is not available yet.
|
||||||
type StatusErr struct {
|
type StatusErr struct {
|
||||||
|
@ -72,20 +95,23 @@ type AuthInfo struct {
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client is the actual implementation of a Kubernetes client.
|
// RESTClient holds common code used to work with API resources that follow the
|
||||||
|
// Kubernetes API pattern
|
||||||
// Host is the http://... base for the URL
|
// Host is the http://... base for the URL
|
||||||
type Client struct {
|
type RESTClient struct {
|
||||||
host string
|
host string
|
||||||
auth *AuthInfo
|
auth *AuthInfo
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
Sync bool
|
Sync bool
|
||||||
PollPeriod time.Duration
|
PollPeriod time.Duration
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
|
Prefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new client object.
|
// NewRESTClient creates a new RESTClient. This client performs generic REST functions
|
||||||
func New(host string, auth *AuthInfo) *Client {
|
// such as Get, Put, Post, and Delete on specified paths.
|
||||||
return &Client{
|
func NewRESTClient(host string, auth *AuthInfo, prefix string) *RESTClient {
|
||||||
|
return &RESTClient{
|
||||||
auth: auth,
|
auth: auth,
|
||||||
host: host,
|
host: host,
|
||||||
httpClient: &http.Client{
|
httpClient: &http.Client{
|
||||||
|
@ -98,11 +124,19 @@ func New(host string, auth *AuthInfo) *Client {
|
||||||
Sync: false,
|
Sync: false,
|
||||||
PollPeriod: time.Second * 2,
|
PollPeriod: time.Second * 2,
|
||||||
Timeout: time.Second * 20,
|
Timeout: time.Second * 20,
|
||||||
|
Prefix: prefix,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a Kubernetes client. This client works with pods, replication controllers
|
||||||
|
// and services. It allows operations such as list, get, update and delete on these objects.
|
||||||
|
func New(host string, auth *AuthInfo) *Client {
|
||||||
|
return &Client{NewRESTClient(host, auth, "/api/v1beta1/")}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a request, adds authentication (if auth != nil), and HTTPS cert ignoring.
|
// Execute a request, adds authentication (if auth != nil), and HTTPS cert ignoring.
|
||||||
func (c *Client) doRequest(request *http.Request) ([]byte, error) {
|
func (c *RESTClient) doRequest(request *http.Request) ([]byte, error) {
|
||||||
if c.auth != nil {
|
if c.auth != nil {
|
||||||
request.SetBasicAuth(c.auth.User, c.auth.Password)
|
request.SetBasicAuth(c.auth.User, c.auth.Password)
|
||||||
}
|
}
|
||||||
|
@ -148,7 +182,7 @@ func (c *Client) doRequest(request *http.Request) ([]byte, error) {
|
||||||
// path is the path on the host to hit
|
// path is the path on the host to hit
|
||||||
// requestBody is the body of the request. Can be nil.
|
// requestBody is the body of the request. Can be nil.
|
||||||
// target the interface to marshal the JSON response into. Can be nil.
|
// target the interface to marshal the JSON response into. Can be nil.
|
||||||
func (c *Client) rawRequest(method, path string, requestBody io.Reader, target interface{}) ([]byte, error) {
|
func (c *RESTClient) rawRequest(method, path string, requestBody io.Reader, target interface{}) ([]byte, error) {
|
||||||
request, err := http.NewRequest(method, c.makeURL(path), requestBody)
|
request, err := http.NewRequest(method, c.makeURL(path), requestBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -167,8 +201,8 @@ func (c *Client) rawRequest(method, path string, requestBody io.Reader, target i
|
||||||
return body, err
|
return body, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) makeURL(path string) string {
|
func (c *RESTClient) makeURL(path string) string {
|
||||||
return c.host + "/api/v1beta1/" + path
|
return c.host + c.Prefix + path
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListPods takes a selector, and returns the list of pods that match that selector
|
// ListPods takes a selector, and returns the list of pods that match that selector
|
||||||
|
|
|
@ -415,7 +415,7 @@ func TestMakeRequest(t *testing.T) {
|
||||||
{Request: testRequest{Method: "GET", Path: "/good"}, Response: Response{StatusCode: 200}},
|
{Request: testRequest{Method: "GET", Path: "/good"}, Response: Response{StatusCode: 200}},
|
||||||
{Request: testRequest{Method: "GET", Path: "/bad%ZZ"}, Error: true},
|
{Request: testRequest{Method: "GET", Path: "/bad%ZZ"}, Error: true},
|
||||||
{Client: New("", &AuthInfo{"foo", "bar"}), Request: testRequest{Method: "GET", Path: "/auth", Header: "Authorization"}, Response: Response{StatusCode: 200}},
|
{Client: New("", &AuthInfo{"foo", "bar"}), Request: testRequest{Method: "GET", Path: "/auth", Header: "Authorization"}, Response: Response{StatusCode: 200}},
|
||||||
{Client: &Client{httpClient: http.DefaultClient}, Request: testRequest{Method: "GET", Path: "/nocertificate"}, Error: true},
|
{Client: &Client{&RESTClient{httpClient: http.DefaultClient}}, Request: testRequest{Method: "GET", Path: "/nocertificate"}, Error: true},
|
||||||
{Request: testRequest{Method: "GET", Path: "/error"}, Response: Response{StatusCode: 500}, Error: true},
|
{Request: testRequest{Method: "GET", Path: "/error"}, Response: Response{StatusCode: 500}, Error: true},
|
||||||
{Request: testRequest{Method: "POST", Path: "/faildecode"}, Response: Response{StatusCode: 200, Body: "aaaaa"}, Target: &struct{}{}, Error: true},
|
{Request: testRequest{Method: "POST", Path: "/faildecode"}, Response: Response{StatusCode: 200, Body: "aaaaa"}, Target: &struct{}{}, Error: true},
|
||||||
{Request: testRequest{Method: "GET", Path: "/failread"}, Response: Response{StatusCode: 200, Body: "aaaaa"}, Target: &struct{}{}, Error: true},
|
{Request: testRequest{Method: "GET", Path: "/failread"}, Response: Response{StatusCode: 200, Body: "aaaaa"}, Target: &struct{}{}, Error: true},
|
||||||
|
|
|
@ -19,6 +19,7 @@ package client
|
||||||
import (
|
import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -110,3 +111,9 @@ func (c *Fake) DeleteService(service string) error {
|
||||||
c.Actions = append(c.Actions, FakeAction{Action: "delete-service", Value: service})
|
c.Actions = append(c.Actions, FakeAction{Action: "delete-service", Value: service})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Fake) ServerVersion() (*version.Info, error) {
|
||||||
|
c.Actions = append(c.Actions, FakeAction{Action: "get-version", Value: nil})
|
||||||
|
versionInfo := version.Get()
|
||||||
|
return &versionInfo, nil
|
||||||
|
}
|
||||||
|
|
|
@ -52,11 +52,11 @@ var specialParams = util.NewStringSet("sync", "timeout")
|
||||||
// if err != nil { ... }
|
// if err != nil { ... }
|
||||||
// list, ok := resp.(*api.PodList)
|
// list, ok := resp.(*api.PodList)
|
||||||
//
|
//
|
||||||
func (c *Client) Verb(verb string) *Request {
|
func (c *RESTClient) Verb(verb string) *Request {
|
||||||
return &Request{
|
return &Request{
|
||||||
verb: verb,
|
verb: verb,
|
||||||
c: c,
|
c: c,
|
||||||
path: "/api/v1beta1",
|
path: c.Prefix,
|
||||||
sync: c.Sync,
|
sync: c.Sync,
|
||||||
timeout: c.Timeout,
|
timeout: c.Timeout,
|
||||||
params: map[string]string{},
|
params: map[string]string{},
|
||||||
|
@ -65,27 +65,27 @@ func (c *Client) Verb(verb string) *Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post begins a POST request. Short for c.Verb("POST").
|
// Post begins a POST request. Short for c.Verb("POST").
|
||||||
func (c *Client) Post() *Request {
|
func (c *RESTClient) Post() *Request {
|
||||||
return c.Verb("POST")
|
return c.Verb("POST")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put begins a PUT request. Short for c.Verb("PUT").
|
// Put begins a PUT request. Short for c.Verb("PUT").
|
||||||
func (c *Client) Put() *Request {
|
func (c *RESTClient) Put() *Request {
|
||||||
return c.Verb("PUT")
|
return c.Verb("PUT")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get begins a GET request. Short for c.Verb("GET").
|
// Get begins a GET request. Short for c.Verb("GET").
|
||||||
func (c *Client) Get() *Request {
|
func (c *RESTClient) Get() *Request {
|
||||||
return c.Verb("GET")
|
return c.Verb("GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete begins a DELETE request. Short for c.Verb("DELETE").
|
// Delete begins a DELETE request. Short for c.Verb("DELETE").
|
||||||
func (c *Client) Delete() *Request {
|
func (c *RESTClient) Delete() *Request {
|
||||||
return c.Verb("DELETE")
|
return c.Verb("DELETE")
|
||||||
}
|
}
|
||||||
|
|
||||||
// PollFor makes a request to do a single poll of the completion of the given operation.
|
// PollFor makes a request to do a single poll of the completion of the given operation.
|
||||||
func (c *Client) PollFor(operationID string) *Request {
|
func (c *RESTClient) PollFor(operationID string) *Request {
|
||||||
return c.Get().Path("operations").Path(operationID).Sync(false).PollPeriod(0)
|
return c.Get().Path("operations").Path(operationID).Sync(false).PollPeriod(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ func (c *Client) PollFor(operationID string) *Request {
|
||||||
// Any errors are stored until the end of your call, so you only have to
|
// Any errors are stored until the end of your call, so you only have to
|
||||||
// check once.
|
// check once.
|
||||||
type Request struct {
|
type Request struct {
|
||||||
c *Client
|
c *RESTClient
|
||||||
err error
|
err error
|
||||||
verb string
|
verb string
|
||||||
path string
|
path string
|
||||||
|
|
|
@ -36,16 +36,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetServerVersion(client *client.Client) (*version.Info, error) {
|
func GetServerVersion(client *client.Client) (*version.Info, error) {
|
||||||
body, err := client.Get().AbsPath("/version").Do().Raw()
|
info, err := client.ServerVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Got error: %v", err)
|
||||||
}
|
}
|
||||||
var info version.Info
|
return info, nil
|
||||||
err = json.Unmarshal(body, &info)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Got '%s': %v", string(body), err)
|
|
||||||
}
|
|
||||||
return &info, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func promptForString(field string, r io.Reader) string {
|
func promptForString(field string, r io.Reader) string {
|
||||||
|
|
Loading…
Reference in New Issue