<p dir="auto">ref <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="114165539" data-permission-text="Title is private" data-url="https://github.com/kubernetes/kubernetes/issues/16560" data-hovercard-type="issue" data-hovercard-url="/kubernetes/kubernetes/issues/16560/hovercard" href="https://github.com/kubernetes/kubernetes/issues/16560">#16560</a> <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="111705231" data-permission-text="Title is private" data-url="https://github.com/kubernetes/kubernetes/issues/15730" data-hovercard-type="pull_request" data-hovercard-url="/kubernetes/kubernetes/pull/15730/hovercard" href="https://github.com/kubernetes/kubernetes/pull/15730">#15730</a><br>
Here is the road-map:</p>
<p dir="auto">Writing Client-gen:</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Generate the common methods, ignore the methods operating on subresources for now</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Unify the signature of the common methods in our individual typed clients</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> Make a test type, then write the test against this type instead of every type</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> manually add the methods that are not common to all typed clients</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> make go2idl track the functions, constants, variables, methods in the input package.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> add a "plural" namer to go2idl</li>
</ul>
<p dir="auto">Using Client-gen:</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> generate the internalversion clientset, to replace pkg/client/clientset/unversioned</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> generate the fake clients to enable testing</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> generate versioned client</li>
</ul>
<p dir="auto">Using generated clientset:</p>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> replace the pkg/client/unversioned/ in controllers</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> replace the pkg/client/unversioned/ in kubelets</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> let controllers use versioned clientset</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> let kubelet use versioned clientset</li>
</ul>
<p dir="auto">cc @kubernetes/goog-csi</p>
<p dir="auto">Background: Client proposal in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="111705231" data-permission-text="Title is private" data-url="https://github.com/kubernetes/kubernetes/issues/15730" data-hovercard-type="pull_request" data-hovercard-url="/kubernetes/kubernetes/pull/15730/hovercard" href="https://github.com/kubernetes/kubernetes/pull/15730">#15730</a>, api type structure proposal in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="112685544" data-permission-text="Title is private" data-url="https://github.com/kubernetes/kubernetes/issues/16062" data-hovercard-type="pull_request" data-hovercard-url="/kubernetes/kubernetes/pull/16062/hovercard" href="https://github.com/kubernetes/kubernetes/pull/16062">#16062</a></p>
<p dir="auto">At first I was thinking we'd generate based on tags in the comments, e.g. something like:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Pod documentation here
// +generate=Create,Update,List,Get,Delete
type Pod struct {
  ...
}"><pre class="notranslate"><span class="pl-c">// Pod documentation here</span>
<span class="pl-c">// +generate=Create,Update,List,Get,Delete</span>
<span class="pl-k">type</span> <span class="pl-smi">Pod</span> <span class="pl-k">struct</span> {
  <span class="pl-c1">...</span>
}</pre></div>
<p dir="auto">And the result would be something like our current PodsNamespacer client. But then I got to thinking that it'd be super nice to have type information in the methods, to handle the case where e.g. the Binding() method takes an *v1.Binding.</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="type PodsREST interface {
  Create(*Pod) *Pod
  Update(*Pod) *Pod
  List(???) *PodList
  Binding(*Binding) *Status
}"><pre class="notranslate"><span class="pl-k">type</span> <span class="pl-smi">PodsREST</span> <span class="pl-k">interface</span> {
  <span class="pl-c1">Create</span>(<span class="pl-c1">*</span><span class="pl-smi">Pod</span>) <span class="pl-c1">*</span><span class="pl-smi">Pod</span>
  <span class="pl-c1">Update</span>(<span class="pl-c1">*</span><span class="pl-smi">Pod</span>) <span class="pl-c1">*</span><span class="pl-smi">Pod</span>
  <span class="pl-c1">List</span>(???) <span class="pl-c1">*</span><span class="pl-smi">PodList</span>
  <span class="pl-c1">Binding</span>(<span class="pl-c1">*</span><span class="pl-smi">Binding</span>) <span class="pl-c1">*</span><span class="pl-smi">Status</span>
}</pre></div>
<p dir="auto">This has some downsides, like how do you represent query parameters, or the fact that you'll either get a *Pod or a *Status (i.e., error) back? Or that that you must POST to Binding?</p>
<p dir="auto">We could model one layer down.</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="type PodsPOST struct {
  Parameters *POSTParams
  ReqBody *Pod
  RespBody *Pod
}

type PodsREST struct {
  POST PodsPOST
  ...
  bindings PodBindingsREST
}

type PodBindingsREST struct {
  POST BindingsPOST
}

type BindingsPOST struct {
  Parameters *POSTParams
  ReqBody *Binding
  RespBody *Status
}"><pre class="notranslate"><span class="pl-k">type</span> <span class="pl-smi">PodsPOST</span> <span class="pl-k">struct</span> {
  <span class="pl-c1">Parameters</span> <span class="pl-c1">*</span><span class="pl-smi">POSTParams</span>
  <span class="pl-c1">ReqBody</span> <span class="pl-c1">*</span><span class="pl-smi">Pod</span>
  <span class="pl-c1">RespBody</span> <span class="pl-c1">*</span><span class="pl-smi">Pod</span>
}

<span class="pl-k">type</span> <span class="pl-smi">PodsREST</span> <span class="pl-k">struct</span> {
  <span class="pl-c1">POST</span> <span class="pl-smi">PodsPOST</span>
  <span class="pl-c1">...</span>
  <span class="pl-c1">bindings</span> <span class="pl-smi">PodBindingsREST</span>
}

<span class="pl-k">type</span> <span class="pl-smi">PodBindingsREST</span> <span class="pl-k">struct</span> {
  <span class="pl-c1">POST</span> <span class="pl-smi">BindingsPOST</span>
}

<span class="pl-k">type</span> <span class="pl-smi">BindingsPOST</span> <span class="pl-k">struct</span> {
  <span class="pl-c1">Parameters</span> <span class="pl-c1">*</span><span class="pl-smi">POSTParams</span>
  <span class="pl-c1">ReqBody</span> <span class="pl-c1">*</span><span class="pl-smi">Binding</span>
  <span class="pl-c1">RespBody</span> <span class="pl-c1">*</span><span class="pl-smi">Status</span>
}</pre></div>
<p dir="auto">This has disadvantages: it's starting to get quite complex and verbose, there's still no good go way to indicate union types.</p>
<p dir="auto">So we need to explore alternatives.</p>
<ul dir="auto">
<li>Always generate clients from swagger? Then we don't need to solve this until we want to generate the rest setup code. This is probably the most obvious thing to do, which is why I'm filing this as only P2.</li>
<li>Switch to proto? The RPC/service stuff there isn't super natural for describing REST either, but it can work. This would be very disruptive, though.</li>
</ul>