<h2 dir="auto">Problem</h2>
<p dir="auto">Our code is riddled with snippets that look like this:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="if err != nil {
  return nil, err
}"><pre class="notranslate"><span class="pl-k">if</span> <span class="pl-s1">err</span> <span class="pl-c1">!=</span> <span class="pl-c1">nil</span> {
  <span class="pl-k">return</span> <span class="pl-c1">nil</span>, <span class="pl-s1">err</span>
}</pre></div>
<p dir="auto">These lines bubble errors up the call stack until someone decides to log them and move on:</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="if err != nil {
  glog.Errorf(&quot;Something failed: %v&quot;, err)
}"><pre class="notranslate"><span class="pl-k">if</span> <span class="pl-s1">err</span> <span class="pl-c1">!=</span> <span class="pl-c1">nil</span> {
  <span class="pl-s1">glog</span>.<span class="pl-en">Errorf</span>(<span class="pl-s">"Something failed: %v"</span>, <span class="pl-s1">err</span>)
}</pre></div>
<p dir="auto">Which can yield an unhelpful error message like (fake, but not totally unreasonable):</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="E0426 01:02:59.506727    2740 manager.go:110] Something failed: unexpected EOF"><pre class="notranslate"><code class="notranslate">E0426 01:02:59.506727    2740 manager.go:110] Something failed: unexpected EOF
</code></pre></div>
<p dir="auto">And now we're tasked with trying to crawl through the code to figure out where that error actually came from.</p>
<p dir="auto">We discourage logging an error that's also returned (duplicate log statements interwoven throughout the code can also be confusing), but if you (the person debugging) is lucky someone has attached a unique context message that can help you find the source (e.g. <code class="notranslate">Operation foo called on pod bar (441234) failed: %v</code>).</p>
<h2 dir="auto">Assumptions</h2>
<ul dir="auto">
<li>Errors are relatively uncommon - i.e. this doesn't apply to "not found" errors that should probably be <code class="notranslate">bool</code>s, or errors which can be generated in a tight loop</li>
<li>Errors are ephemeral - that is, they are handled (e.g. logged) and then discarded (not stored anywhere)</li>
<li>When an error is produced, it is not always possible to know how it will be handled, or even how severe it is</li>
</ul>
<h2 dir="auto">Proposal</h2>
<p dir="auto">From the above assumptions, I get 2 guiding principles:</p>
<ol dir="auto">
<li>If returning an error, it is your job to provide the maximum amount of debugging information and context around that error.</li>
<li>If handling an error, it is your job to use the <em>appropriate</em> context for the specific case (e.g. a critical failure should have more detail than something that is expected to occassionally fail and will be retried).</li>
</ol>
<p dir="auto">To this end, I'd like to create a kubernetes error package that we promote everywhere. The constructor could look something like (rough sketch, not final API):</p>
<div class="highlight highlight-source-go notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="func New(msg string, context ...Context) Error { ... } // Context TBD
func Wrap(msg string, err error, context ...Context) Error { ... }"><pre class="notranslate"><span class="pl-k">func</span> <span class="pl-en">New</span>(<span class="pl-s1">msg</span> <span class="pl-smi">string</span>, <span class="pl-s1">context</span> <span class="pl-c1">...</span><span class="pl-smi">Context</span>) <span class="pl-smi">Error</span> { <span class="pl-c1">...</span> } <span class="pl-c">// Context TBD</span>
<span class="pl-k">func</span> <span class="pl-en">Wrap</span>(<span class="pl-s1">msg</span> <span class="pl-smi">string</span>, <span class="pl-s1">err</span> <span class="pl-smi">error</span>, <span class="pl-s1">context</span> <span class="pl-c1">...</span><span class="pl-smi">Context</span>) <span class="pl-smi">Error</span> { <span class="pl-c1">...</span> }</pre></div>
<p dir="auto">In addition to the provided message, error, and context the constructors could automatically attach additional metadata such as: a full stack trace, timestamp, etc.</p>
<p dir="auto">We would also provide formatting functions that could flatten the error objects and format them to various levels of detail for logging. Finally, to get the maximum benefit, we would want to discourage the pattern of returning a raw error without first wrapping it with extra context.</p>
<p dir="auto">For implementation, there are already several projects which provide similar functionality:</p>
<ul dir="auto">
<li><a href="https://github.com/go-errors/errors">https://github.com/go-errors/errors</a> (<a href="http://blog.bugsnag.com/go-errors" rel="nofollow">blog</a>)</li>
<li><a href="https://github.com/hashicorp/errwrap">https://github.com/hashicorp/errwrap</a></li>
</ul>
<p dir="auto">X-ref: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="66523592" data-permission-text="Title is private" data-url="https://github.com/kubernetes/kubernetes/issues/6461" data-hovercard-type="issue" data-hovercard-url="/kubernetes/kubernetes/issues/6461/hovercard" href="https://github.com/kubernetes/kubernetes/issues/6461">#6461</a>, <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="142710553" data-permission-text="Title is private" data-url="https://github.com/kubernetes/kubernetes/issues/23338" data-hovercard-type="issue" data-hovercard-url="/kubernetes/kubernetes/issues/23338/hovercard" href="https://github.com/kubernetes/kubernetes/issues/23338">#23338</a> - This proposal is independent of which log library we use, we just need to provide functions to log the appropriate context in whatever format.</p>
<p dir="auto">/cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/thockin/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/thockin">@thockin</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/timothysc/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/timothysc">@timothysc</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/pwittrock/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/pwittrock">@pwittrock</a> <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/bgrant0607/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/bgrant0607">@bgrant0607</a></p>
<p dir="auto"><strong>What keywords did you search in Kubernetes issues before filing this one?</strong> (If you have found any duplicates, you should instead reply there.): external service</p>
<p dir="auto"><strong>Kubernetes version</strong> (use <code class="notranslate">kubectl version</code>):<br>
v1.5.0-alpha.0.2084+162d80eced3989</p>
<p dir="auto"><strong>What happened</strong>:<br>
ExternalName type service cannot be created if without <code class="notranslate">spec.ports</code>.</p>
<p dir="auto"><strong>How to reproduce it</strong> (as minimally and precisely as possible):<br>
Create a ExternalName type service: <code class="notranslate">kubectl create -f ExternalName type service</code></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{
    &quot;kind&quot;: &quot;Service&quot;,
    &quot;apiVersion&quot;: &quot;v1&quot;,
    &quot;metadata&quot;: {
        &quot;name&quot;: &quot;my-service&quot;
    },
    &quot;spec&quot;: {
        &quot;type&quot;: &quot;ExternalName&quot;,
        &quot;externalName&quot;: &quot;my.database.example.com&quot;
    }
}"><pre class="notranslate"><code class="notranslate">{
    "kind": "Service",
    "apiVersion": "v1",
    "metadata": {
        "name": "my-service"
    },
    "spec": {
        "type": "ExternalName",
        "externalName": "my.database.example.com"
    }
}
</code></pre></div>
<p dir="auto"><strong>Actual results</strong>:<br>
ExternalName type service created failed.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="# kubectl create -f externalname-service.json
error: error validating &quot;externalname-service.json&quot;: error validating data: field ports: is required; if you choose to ignore these errors, turn validation off with --validate=false"><pre class="notranslate"><code class="notranslate"># kubectl create -f externalname-service.json
error: error validating "externalname-service.json": error validating data: field ports: is required; if you choose to ignore these errors, turn validation off with --validate=false
</code></pre></div>
<p dir="auto"><strong>Expected results</strong>:<br>
Service should be created successful.</p>
<p dir="auto"><strong>Anything else do we need to know</strong>:<br>
You can refer to the docs about externalname type service: <a href="https://github.com/kubernetes/kubernetes.github.io/blob/release-1.4/docs/user-guide/services/index.md">https://github.com/kubernetes/kubernetes.github.io/blob/release-1.4/docs/user-guide/services/index.md</a><br>
The docs indicated that <code class="notranslate">An ExternalName service is a special case of service that does not have selectors. It does not define any ports or endpoints. Rather, it serves as a way to return an alias to an external service residing outside the cluster.</code></p>