Skip to content

Automatic API generation via go-restful#2282

Merged
lavalamp merged 1 commit intokubernetes:masterfrom
bgrant0607:docgen
Nov 14, 2014
Merged

Automatic API generation via go-restful#2282
lavalamp merged 1 commit intokubernetes:masterfrom
bgrant0607:docgen

Conversation

@bgrant0607
Copy link
Copy Markdown
Member

Partially addresses #1052.

There's lots more work left to do here, but I got this working, so I thought I'd share it.

go-restful provides a more structured handler registration mechanism, with the ability to document a number of aspects of the API. The object definitions are extracted via reflection and their descriptions are extracted from field tags (added by the author of go-restful upon my request). It uses https://github.com/swagger-api/swagger-ui for the doc UI, and also provides a discovery API that can be used to query available endpoints and json schemas.

In order for the initial version of this to be merged, two main things need to be done:

  1. Fix apiserver_test and make all the tests pass
  2. Update and merge the PR that adds go-restful to Godeps

Beyond that, I'd like to iterate on cleaning this up and adding documentation in other PRs:

  • Customize the swagger UI for our needs
  • Figure out how to copy https://github.com/swagger-api/swagger-ui/dist to the master
  • Figure out what to do with the custom verbs (watch, proxy, redirect)
  • Convert all handlers to native go-restful style
  • Convert handler parameters to go-restful parameters
  • Perhaps split REST handlers into per-verb handlers
  • Add descriptions to all handlers
  • Add description tags to all types.go object fields
  • Add documentation of other details (return codes, input/output mime types, etc.)
  • Fix go-restful bugs

/cc @lavalamp @smarterclayton @erictune

Comment thread pkg/apiserver/apiserver.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flexibility, no other reason.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took away that flexibility for now. We can add it back later if needed.

@bgrant0607 bgrant0607 changed the title WIP: Automatic API generation via go-restful Automatic API generation via go-restful Nov 12, 2014
@bgrant0607
Copy link
Copy Markdown
Member Author

Will rebase and squash once #2222 is merged.

Comment thread pkg/apiserver/apiserver.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use path.Join

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@bgrant0607
Copy link
Copy Markdown
Member Author

Rebase is now pushed. PTAL.

Comment thread pkg/apiserver/apiserver.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can condense the above with .Infof("InstallREST: %v kinds: %#v", version, kinds)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@lavalamp
Copy link
Copy Markdown
Contributor

missing gofmt. I'd like to give this another look-through before it's merged, I'm still digesting that gigantic function...

@bgrant0607
Copy link
Copy Markdown
Member Author

Feedback addressed.

@smarterclayton
Copy link
Copy Markdown
Contributor

Same here - promise to look in morning.

On Nov 12, 2014, at 9:25 PM, Daniel Smith notifications@github.com wrote:

missing gofmt. I'd like to give this another look-through before it's merged, I'm still digesting that gigantic function...


Reply to this email directly or view it on GitHub.

@bgrant0607
Copy link
Copy Markdown
Member Author

verify-gofmt and e2e pass in my sandbox. Not sure what's up with Travis.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Consume takes as many mime types as you want. So maybe enumerate the ones we take rather than accept all?

Now, the question is what mime type(s) YAML is.
I think ws.Consumes(restful.MIME_JSON, "application/x-yaml", "text/yaml") should do it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Consume takes an arbitrary number of types. However, not all clients set a content type at all, and there is no standard yaml type. I figure this can be fixed in a follow-up PR, after we get our client library and tools squared away.

@erictune
Copy link
Copy Markdown
Contributor

Didn't do a super detailed review, but looks good overall.

You can git rid of the whoami handler if it is causing you trouble. I haven't needed it like I thought I would.

@bgrant0607
Copy link
Copy Markdown
Member Author

Thanks @erictune. I know there's lots more to do, but I'm just trying to get in the minimal viable change before other PRs break it again. It will be easier to iterate on it once it's merged.

@bgrant0607
Copy link
Copy Markdown
Member Author

Could I be running a different version of gofmt than Travis? Travis complains:

!!! gofmt needs to be run on the following files: 
./pkg/client/containerinfo_test.go
./pkg/apiserver/apiserver.go

I ran gofmt on these 2 files and pushed them because verify-gofmt complained on my system. However, how Travis complains about them. gofmt doesn't have a --version flag. The change to the first file looks like:

--- a/pkg/client/containerinfo_test.go
+++ b/pkg/client/containerinfo_test.go
@@ -114,7 +114,7 @@ func TestHTTPContainerInfoGetterGetContainerInfoSuccessfully(t *testing.T) {
        }
        cinfo := itest.GenerateRandomContainerInfo(
                "dockerIDWhichWillNotBeChecked", // docker ID
-               2, // Number of cores
+               2,                               // Number of cores
                req,
                1*time.Second,
        )
@@ -127,7 +127,7 @@ func TestHTTPContainerInfoGetterGetRootInfoSuccessfully(t *testing.T) {
        }
        cinfo := itest.GenerateRandomContainerInfo(
                "dockerIDWhichWillNotBeChecked", // docker ID
-               2, // Number of cores
+               2,                               // Number of cores
                req,
                1*time.Second,
        )
@@ -140,7 +140,7 @@ func TestHTTPContainerInfoGetterGetContainerInfoWithError(t *testing.T) {
        }
        cinfo := itest.GenerateRandomContainerInfo(
                "dockerIDWhichWillNotBeChecked", // docker ID
-               2, // Number of cores
+               2,                               // Number of cores
                req,
                1*time.Second,
        )
@@ -153,7 +153,7 @@ func TestHTTPContainerInfoGetterGetRootInfoWithError(t *testing.T) {
        }
        cinfo := itest.GenerateRandomContainerInfo(
                "dockerIDWhichWillNotBeChecked", // docker ID
-               2, // Number of cores
+               2,                               // Number of cores
                req,
                1*time.Second,
        )

and to the second:

--- a/test/integration/auth_test.go
+++ b/test/integration/auth_test.go
@@ -321,7 +321,7 @@ func getTestRequests() []struct {
                {"DELETE", "/api/v1beta1/events/a" + syncFlags, "", code200},

                // Normal methods on bindings
-               {"GET", "/api/v1beta1/bindings", "", code405},            // Bindings are write-only
+               {"GET", "/api/v1beta1/bindings", "", code405},     // Bindings are write-only
                {"POST", "/api/v1beta1/pods" + syncFlags, aPod, code200}, // Need a pod to bind or you get a 404
                {"POST", "/api/v1beta1/bindings" + syncFlags, aBinding, code200},
                {"PUT", "/api/v1beta1/bindings/a" + syncFlags, aBinding, code500}, // See #2114 about why 500

@erictune
Copy link
Copy Markdown
Contributor

Did you forget that you have to stage files again after running gofmt?
Sometimes I forget this. Check if you have uncommitted changes to those
files.

On Wed, Nov 12, 2014 at 10:05 PM, bgrant0607 notifications@github.com
wrote:

Could I be running a different version of gofmt than Travis? Travis
complains:

!!! gofmt needs to be run on the following files:
./pkg/client/containerinfo_test.go
./pkg/apiserver/apiserver.go

I ran gofmt on these 2 files and pushed them because verify-gofmt
complained on my system. However, how Travis complains about them. gofmt
doesn't have a --version flag. The change to the first file looks like:

--- a/pkg/client/containerinfo_test.go
+++ b/pkg/client/containerinfo_test.go
@@ -114,7 +114,7 @@ func TestHTTPContainerInfoGetterGetContainerInfoSuccessfully(t *testing.T) {
}
cinfo := itest.GenerateRandomContainerInfo(
"dockerIDWhichWillNotBeChecked", // docker ID

  •           2, // Number of cores
    
  •           2,                               // Number of cores
            req,
            1*time.Second,
    )
    
    @@ -127,7 +127,7 @@ func TestHTTPContainerInfoGetterGetRootInfoSuccessfully(t *testing.T) {
    }
    cinfo := itest.GenerateRandomContainerInfo(
    "dockerIDWhichWillNotBeChecked", // docker ID
  •           2, // Number of cores
    
  •           2,                               // Number of cores
            req,
            1*time.Second,
    )
    
    @@ -140,7 +140,7 @@ func TestHTTPContainerInfoGetterGetContainerInfoWithError(t *testing.T) {
    }
    cinfo := itest.GenerateRandomContainerInfo(
    "dockerIDWhichWillNotBeChecked", // docker ID
  •           2, // Number of cores
    
  •           2,                               // Number of cores
            req,
            1*time.Second,
    )
    
    @@ -153,7 +153,7 @@ func TestHTTPContainerInfoGetterGetRootInfoWithError(t *testing.T) {
    }
    cinfo := itest.GenerateRandomContainerInfo(
    "dockerIDWhichWillNotBeChecked", // docker ID
  •           2, // Number of cores
    
  •           2,                               // Number of cores
            req,
            1*time.Second,
    )
    

and to the second:

--- a/test/integration/auth_test.go
+++ b/test/integration/auth_test.go
@@ -321,7 +321,7 @@ func getTestRequests() []struct {
{"DELETE", "/api/v1beta1/events/a" + syncFlags, "", code200},

            // Normal methods on bindings
  •           {"GET", "/api/v1beta1/bindings", "", code405},            // Bindings are write-only
    
  •           {"GET", "/api/v1beta1/bindings", "", code405},     // Bindings are write-only
            {"POST", "/api/v1beta1/pods" + syncFlags, aPod, code200}, // Need a pod to bind or you get a 404
            {"POST", "/api/v1beta1/bindings" + syncFlags, aBinding, code200},
            {"PUT", "/api/v1beta1/bindings/a" + syncFlags, aBinding, code500}, // See #2114 about why 500
    


Reply to this email directly or view it on GitHub
#2282 (comment)
.

@bgrant0607
Copy link
Copy Markdown
Member Author

I have no unpushed changes. If you look at the commit history, it's the pushes of gofmt changes that caused the Travis failures.

@erictune
Copy link
Copy Markdown
Contributor

For the container_info_test.go, try introducing a newline above and below
the offending line to disable gofmt from aligning it.

For apiserver.go, you pasted the wrong thing in your mail, but maybe the
same thing will work.

On Wed, Nov 12, 2014 at 10:17 PM, bgrant0607 notifications@github.com
wrote:

I have no unpushed changes. If you look at the commit history, it's the
pushes of gofmt changes that caused the Travis failures.


Reply to this email directly or view it on GitHub
#2282 (comment)
.

Comment thread pkg/api/unversioned.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if they're unversioned we can't evolve them without introducing new fields and deprecating old ones. I'm somewhat scared about introducing these until we have a good idea what they should be doing, because we can't change them in a version compatible way. Do you have confidence these are the right objects?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already return APIVersions. This just moves it.

APIResources could be versioned, I suppose.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented out APIResources and added TODOs for now.

Comment thread pkg/master/master.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having to do this seems to defeat the purpose of taking apiserver.Mux.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Fixed.

@bgrant0607
Copy link
Copy Markdown
Member Author

I did have an incompatible version of gofmt in my path. Now using the gofmt from go 1.3.

@bgrant0607
Copy link
Copy Markdown
Member Author

Travis is green. All feedback addressed.

@mindscratch
Copy link
Copy Markdown

just want to throw in my +1

@smarterclayton
Copy link
Copy Markdown
Contributor

Can you update your commit message to not be WIP and remove the error? Seems like it's busted

@lavalamp
Copy link
Copy Markdown
Contributor

gofmt: it did change at some point; I forget what version we standardized on. It follows your go version.

I have version 1.3.

Comment thread pkg/apiserver/apiserver.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a readability standpoint, I think it would be great if the body of this loop were moved into its own function, e.g., installSingleHandler or some such. I'm ok merging without this if it will get cleaned up soon, although I'm feeling like in general promised cleanup has not been happening at the promised rate and I'm getting reluctant to say things like this...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need a cleanup week.

On Nov 13, 2014, at 3:48 PM, Daniel Smith notifications@github.com wrote:

In pkg/apiserver/apiserver.go:

  • // create one for the tests, also
  • // Success:
  • // http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNoContent
  • //
  • // test/integration/auth_test.go is currently the most comprehensive status code test
  • // TODO: eliminate all the restful wrappers
  • // TODO: create a separate handler per verb
  • h := func(req *restful.Request, resp *restful.Response) {
  •   glog.V(3).Infof("User-Agent: %s\n", req.HeaderParameter("User-Agent"))
    
  •   strippedHandler.ServeHTTP(resp.ResponseWriter, req.Request)
    
  • }
  • // TODO: factor out per-kind code
  • for path, storage := range g.handler.storage {
  •   glog.V(3).Infof("Installing /%s/%s\n", version, path)
    
    From a readability standpoint, I think it would be great if the body of this loop were moved into its own function, e.g., installSingleHandler or some such. I'm ok merging without this if it will get cleaned up soon, although I'm feeling like in general promised cleanup has not been happening at the promised rate and I'm getting reluctant to say things like this...


Reply to this email directly or view it on GitHub.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll refactor it now, esp. since it won't be merged until tomorrow, anyway.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, much appreciated

@lavalamp
Copy link
Copy Markdown
Contributor

LGTM with responses to my last two comments.

@bgrant0607
Copy link
Copy Markdown
Member Author

Feedback addressed, but now I'm having a really weird gofmt issue. I get a gofmt error that prevents me from rebasing, even though I've removed the old gofmt binary and even if I specify --no-verify AND remove the prepare-commit-msg hooks. Sigh.

@bgrant0607
Copy link
Copy Markdown
Member Author

Learned enough git to make the rebase work, and reinstalled go on my system for good measure. Ok to merge now?

@smarterclayton
Copy link
Copy Markdown
Contributor

About to merge, rerunning travis in case a fluke occured.

@bgrant0607
Copy link
Copy Markdown
Member Author

@smarterclayton Travis is green both on head and on this PR. Did you see a failure earlier?

@lavalamp
Copy link
Copy Markdown
Contributor

LGTM, thanks for rearranging.

lavalamp added a commit that referenced this pull request Nov 14, 2014
Automatic API generation via go-restful
@lavalamp lavalamp merged commit 9430bb3 into kubernetes:master Nov 14, 2014
@smarterclayton
Copy link
Copy Markdown
Contributor

I'm in the habit of rebuilding Travis right before big refactor merges now because Travis won't rebuild if someone else delivers function. Bit me a few times.

On Nov 14, 2014, at 3:59 PM, bgrant0607 notifications@github.com wrote:

@smarterclayton Travis is green both on head and on this PR. Did you see a failure earlier?


Reply to this email directly or view it on GitHub.

bertinatto pushed a commit to bertinatto/kubernetes that referenced this pull request May 7, 2025
…-disabled-older-kubelet-ocp-master

OCPBUGS-55632: Fix node expansion on older kubelets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants