<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Open Infrastructure Services LLC – OIS Blog</title><link>http://openinfrastructure.co/blog/</link><description>Recent content in OIS Blog on Open Infrastructure Services LLC</description><generator>Hugo -- gohugo.io</generator><atom:link href="http://openinfrastructure.co/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: Privacy Policy</title><link>http://openinfrastructure.co/blog/2023/05/23/privacy-policy/</link><pubDate>Tue, 23 May 2023 12:00:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2023/05/23/privacy-policy/</guid><description>
&lt;p>&lt;em>Last Updated: January, 2025&lt;/em>&lt;/p>
&lt;p>&lt;strong>Privacy Policy of Open Infrastructure Services LLC&lt;/strong>&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>We at Open Infrastructure Services LLC respect your privacy and are committed to protecting your personal data. This privacy policy will inform you about how we look after your personal data when you visit our website (regardless of where you visit it from) and tell you about your privacy rights and how the law protects you.&lt;/p>
&lt;h2 id="important-information-and-who-we-are">Important Information and Who We Are&lt;/h2>
&lt;p>Open Infrastructure Services LLC provides custom software development and consulting services. This privacy policy aims to give you information on how Open Infrastructure Services LLC collects and processes your personal data through your use of this website, including any data you may provide through this website.&lt;/p>
&lt;h2 id="the-data-we-collect-about-you">The Data We Collect About You&lt;/h2>
&lt;p>We may collect, use, store, and transfer different kinds of personal data about you, which we have grouped together as follows:&lt;/p>
&lt;ul>
&lt;li>Identity Data includes first name, last name, username, or similar identifier.&lt;/li>
&lt;li>Contact Data includes email address and telephone numbers.&lt;/li>
&lt;li>Technical Data includes internet protocol (IP) address, your login data, browser type and version, time zone setting and location, browser plug-in types and versions, operating system and platform, and other technology on the devices you use to access this website.&lt;/li>
&lt;/ul>
&lt;p>Customer personal data for all of our products and services is transferred to
the United States for login credential management and support both of which may
be performed by US-based resources.&lt;/p>
&lt;h2 id="how-is-your-personal-data-collected">How Is Your Personal Data Collected?&lt;/h2>
&lt;p>We use different methods to collect data from and about you, including through:&lt;/p>
&lt;ul>
&lt;li>Direct interactions. You may give us your Identity, Contact, and Financial Data by filling in forms or by corresponding with us by post, phone, email, or otherwise.&lt;/li>
&lt;li>Automated technologies or interactions. As you interact with our website, we may automatically collect Technical Data about your equipment, browsing actions, and patterns.&lt;/li>
&lt;/ul>
&lt;h2 id="how-we-use-your-personal-data">How We Use Your Personal Data&lt;/h2>
&lt;p>We will only use your personal data when the law allows us to. Most commonly, we will use your personal data in the following circumstances:&lt;/p>
&lt;ul>
&lt;li>Where we need to perform the contract we are about to enter into or have entered into with you.&lt;/li>
&lt;li>Where it is necessary for our legitimate interests (or those of a third party) and your interests and fundamental rights do not override those interests.&lt;/li>
&lt;li>Where we need to comply with a legal obligation.&lt;/li>
&lt;/ul>
&lt;h2 id="data-security">Data Security&lt;/h2>
&lt;p>We have put in place appropriate security measures to prevent your personal data from being accidentally lost, used, or accessed in an unauthorized way, altered, or disclosed.&lt;/p>
&lt;h2 id="your-rights">Your Rights&lt;/h2>
&lt;p>We recognize, under the EU-U.S. Data Privacy Framework Principles, the
Swiss-U.S.Data Privacy Framework Principles, CCPA, the EU GDPR, the UK GDPR, the
Brazilian General Data Protection Law (LGPD), and other applicable privacy laws,
that you may have certain rights in regards to your Personal Information. We
feel that your privacy and ability to preserve and exercise your rights is
important. You are encouraged to review and understand these rights as they
pertain to you and your Personal Information. In certain circumstances, these
rights include, but are not limited to:&lt;/p>
&lt;ul>
&lt;li>Right to be Informed: This means we have to tell you why we process your Personal Information, our retention periods, and who it will be shared with.&lt;/li>
&lt;li>Right to Access: This means we have to provide you with a copy of your Personal Information we process upon your request.&lt;/li>
&lt;li>Right to Rectification: This allows you to have inaccurate Personal Information rectified, or completed if it is incomplete.&lt;/li>
&lt;li>Right to Erasure: This allows you to have your Personal Information erased.&lt;/li>
&lt;li>Right to Restrict Processing: This means you can limit the way we use their data.&lt;/li>
&lt;li>Right to Data Portability: This allows you to receive a copy of your Personal Information in a structured, commonly used and machine-readable format and gives you the right to transmit the data to another controller without hindrance.&lt;/li>
&lt;li>Right to Object: This allows you to object to the processing of your Personal Information at any time.&lt;/li>
&lt;li>Right to Non-Discrimination: The CPRA prohibits covered businesses from discriminating against consumers for exercising their CPRA rights. This means we cannot charge a different price, deny access to our products, or impose penalties for exercising your rights under the CPRA.&lt;/li>
&lt;li>Right to Withdraw Consent: This means you can withdraw your consent at any time.&lt;/li>
&lt;/ul>
&lt;p>In support of these rights, you may exercise any of the above rights, with
respect to your Personal Information. You may update, correct, or delete your
Personal Information; if you wish to delete or suspend your account, please note
that we may retain certain information as required by law or for legitimate
business purposes. If you have become aware that an account has been created
about you without your knowledge or consent, you may contact us to request
deletion of that said account. You may contact us by emailing
&lt;a href="mailto:privacy@openinfrastructure.co">privacy@openinfrastructure.co&lt;/a>&lt;/p>
&lt;p>For your protection, we may only respond with the Personal Information
associated with the particular email address that you use to send us your
request, and we may need to verify your identity before implementing your
request. We will respond to your request within 30 days.&lt;/p>
&lt;h2 id="third-party-links">Third-party Links&lt;/h2>
&lt;p>This website may include links to third-party websites, plug-ins, and
applications. Clicking on those links or enabling those connections may allow
third parties to collect or share data about you. We do not control these
third-party websites and are not responsible for their privacy statements.&lt;/p>
&lt;h2 id="third-party-subprocessors">Third-Party Subprocessors&lt;/h2>
&lt;p>Available on Request&lt;/p>
&lt;h2 id="contact-us">Contact Us&lt;/h2>
&lt;p>For any and all privacy-related matters, questions or comments, or to exercise a
right under the EU’s GDPR, the UK’s GDPR or the CCPA, you may contact us in
writing or by email. Our contact information is as follow:&lt;/p>
&lt;p>Open Infrastructure Services, LLC&lt;/p>
&lt;p>1675 SW MARLOW AVE STE 404&lt;/p>
&lt;p>Portland, OR 97225&lt;/p>
&lt;p>United States&lt;/p>
&lt;p>Phone: +1 (669) 444-1014&lt;/p>
&lt;p>Email: &lt;a href="mailto:privacy@openinfrastructure.co">privacy@openinfrastructure.co&lt;/a>&lt;/p>
&lt;p>Website: &lt;a href="https://openinfrastructure.co">https://openinfrastructure.co&lt;/a>&lt;/p>
&lt;p>In compliance with the EU-U.S. DPF and the UK Extension to the EU-U.S. DPF and
the Swiss-U.S. DPF, Open Infrastructure Services LLC commits to resolve DPF
Principles-related complaints about our collection and use of your personal
information. EU and UK individuals and Swiss individuals with inquiries or
complaints regarding our handling of personal data received in reliance on the
EU-U.S. DPF and the UK Extension to the EU-U.S. DPF, and the Swiss-U.S. DPF
should first contact Open Infrastructure Services LLC at:
&lt;a href="mailto:privacy@openinfrastructure.co">privacy@openinfrastructure.co&lt;/a>.&lt;/p>
&lt;p>If these processes do not result in a resolution, you may then contact your
local data protection authority, the U.S. Department of Commerce, and/or the
Federal Trade Commission for assistance.&lt;/p>
&lt;h2 id="changes-to-the-privacy-policy">Changes to the Privacy Policy&lt;/h2>
&lt;p>We may update this privacy policy from time to time. We encourage you to review
this privacy policy frequently to be informed of how we are protecting your
information.&lt;/p></description></item><item><title>Blog: FastAPI/Starlette OIDC Authentication</title><link>http://openinfrastructure.co/blog/2023/03/28/fastapi/starlette-oidc-authentication/</link><pubDate>Tue, 28 Mar 2023 12:00:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2023/03/28/fastapi/starlette-oidc-authentication/</guid><description>
&lt;p>This post demonstrates how to validate a bearer token issued by an oidc provider. Assume the oauth flow is handled downstream. Starlette&amp;rsquo;s AuthenticationMiddleware is used to attach a SimpleUser and AuthCredentials instance to each request. Authlib validates the iss, exp, and aud claims. Starlette&amp;rsquo;s require decorator authorizes access token scopes.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e4e4e"># main.py&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> fastapi &lt;span style="color:#d75f00">import&lt;/span> FastAPI, Request
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> .middleware &lt;span style="color:#d75f00">import&lt;/span> middleware
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> starlette.authentication &lt;span style="color:#d75f00">import&lt;/span> requires
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> starlette.requests &lt;span style="color:#d75f00">import&lt;/span> Request
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app = FastAPI(middleware=middleware)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0087ff">@app.get&lt;/span>(&lt;span style="color:#00afaf">&amp;#34;/&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5f8700">async&lt;/span> &lt;span style="color:#5f8700">def&lt;/span> &lt;span style="color:#0087ff">homepage&lt;/span>(request: Request):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">if&lt;/span> request.user.is_authenticated:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">return&lt;/span> {&lt;span style="color:#00afaf">&amp;#34;username&amp;#34;&lt;/span>: request.user.username, &lt;span style="color:#00afaf">&amp;#34;anonymous&amp;#34;&lt;/span>: &lt;span style="color:#d75f00">False&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">return&lt;/span> {&lt;span style="color:#00afaf">&amp;#34;anonymous&amp;#34;&lt;/span>: &lt;span style="color:#d75f00">True&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0087ff">@app.get&lt;/span>(&lt;span style="color:#00afaf">&amp;#34;/profile/&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0087ff">@requires&lt;/span>(scopes=[&lt;span style="color:#00afaf">&amp;#34;profile&amp;#34;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5f8700">async&lt;/span> &lt;span style="color:#5f8700">def&lt;/span> &lt;span style="color:#0087ff">profile&lt;/span>(request: Request):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">return&lt;/span> {&lt;span style="color:#00afaf">&amp;#34;user&amp;#34;&lt;/span>: request.user, &lt;span style="color:#00afaf">&amp;#34;auth&amp;#34;&lt;/span>: request.auth}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e4e4e"># middleware.py&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">import&lt;/span> json
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">import&lt;/span> logging
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> functools &lt;span style="color:#d75f00">import&lt;/span> lru_cache
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> threading &lt;span style="color:#d75f00">import&lt;/span> Timer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> urllib.request &lt;span style="color:#d75f00">import&lt;/span> urlopen
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> authlib.jose.rfc7517.jwk &lt;span style="color:#d75f00">import&lt;/span> JsonWebKey, KeySet
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> authlib.oauth2 &lt;span style="color:#d75f00">import&lt;/span> OAuth2Error, ResourceProtector
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> authlib.oauth2.rfc6749 &lt;span style="color:#d75f00">import&lt;/span> MissingAuthorizationError
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> authlib.oauth2.rfc7523 &lt;span style="color:#d75f00">import&lt;/span> JWTBearerTokenValidator
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> authlib.oauth2.rfc7523.validator &lt;span style="color:#d75f00">import&lt;/span> JWTBearerToken
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> fastapi &lt;span style="color:#d75f00">import&lt;/span> Request
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> pydantic &lt;span style="color:#d75f00">import&lt;/span> BaseSettings, Field
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> starlette.authentication &lt;span style="color:#d75f00">import&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> AuthCredentials,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> AuthenticationBackend,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> AuthenticationError,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> SimpleUser,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> starlette.middleware &lt;span style="color:#d75f00">import&lt;/span> Middleware
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> starlette.middleware.authentication &lt;span style="color:#d75f00">import&lt;/span> AuthenticationMiddleware
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d75f00">from&lt;/span> starlette.requests &lt;span style="color:#d75f00">import&lt;/span> HTTPConnection, Request
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>logger = logging.getLogger(__name__)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5f8700">class&lt;/span> &lt;span style="color:#0087ff">Settings&lt;/span>(BaseSettings):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> secret_key: &lt;span style="color:#0087ff">str&lt;/span> = Field(title=&lt;span style="color:#00afaf">&amp;#34;Starlette SessionMiddleware Secret Key&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> oidc_issuer: &lt;span style="color:#0087ff">str&lt;/span> = Field(title=&lt;span style="color:#00afaf">&amp;#34;OIDC Issuer&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> oidc_audience: &lt;span style="color:#0087ff">str&lt;/span> = Field(title=&lt;span style="color:#00afaf">&amp;#34;OIDC Audience&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">class&lt;/span> &lt;span style="color:#0087ff">Config&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> env_file = &lt;span style="color:#00afaf">&amp;#34;.env&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>settings = Settings()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5f8700">class&lt;/span> &lt;span style="color:#0087ff">RepeatTimer&lt;/span>(Timer):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">def&lt;/span> __init__(&lt;span style="color:#0087ff">self&lt;/span>, *args, **kwargs) -&amp;gt; &lt;span style="color:#d75f00">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">super&lt;/span>().__init__(*args, **kwargs)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>.daemon = &lt;span style="color:#d75f00">True&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">def&lt;/span> &lt;span style="color:#0087ff">run&lt;/span>(&lt;span style="color:#0087ff">self&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">while&lt;/span> &lt;span style="color:#5f8700">not&lt;/span> &lt;span style="color:#0087ff">self&lt;/span>.finished.wait(&lt;span style="color:#0087ff">self&lt;/span>.interval):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>.function(*&lt;span style="color:#0087ff">self&lt;/span>.args, **&lt;span style="color:#0087ff">self&lt;/span>.kwargs)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5f8700">class&lt;/span> &lt;span style="color:#0087ff">BearerTokenValidator&lt;/span>(JWTBearerTokenValidator):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">def&lt;/span> __init__(&lt;span style="color:#0087ff">self&lt;/span>, issuer: &lt;span style="color:#0087ff">str&lt;/span>, audience: &lt;span style="color:#0087ff">str&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>._issuer = issuer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>._jwks_uri: &lt;span style="color:#0087ff">str&lt;/span> | &lt;span style="color:#d75f00">None&lt;/span> = &lt;span style="color:#d75f00">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">super&lt;/span>().__init__(public_key=&lt;span style="color:#0087ff">self&lt;/span>.fetch_key(), issuer=issuer)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>.claims_options = {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00afaf">&amp;#34;exp&amp;#34;&lt;/span>: {&lt;span style="color:#00afaf">&amp;#34;essential&amp;#34;&lt;/span>: &lt;span style="color:#d75f00">True&lt;/span>},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00afaf">&amp;#34;aud&amp;#34;&lt;/span>: {&lt;span style="color:#00afaf">&amp;#34;essential&amp;#34;&lt;/span>: &lt;span style="color:#d75f00">True&lt;/span>, &lt;span style="color:#00afaf">&amp;#34;value&amp;#34;&lt;/span>: audience},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00afaf">&amp;#34;iss&amp;#34;&lt;/span>: {&lt;span style="color:#00afaf">&amp;#34;essential&amp;#34;&lt;/span>: &lt;span style="color:#d75f00">True&lt;/span>, &lt;span style="color:#00afaf">&amp;#34;value&amp;#34;&lt;/span>: issuer},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>._timer = RepeatTimer(&lt;span style="color:#00afaf">3600&lt;/span>, &lt;span style="color:#0087ff">self&lt;/span>.refresh)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>._timer.start()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">def&lt;/span> &lt;span style="color:#0087ff">refresh&lt;/span>(&lt;span style="color:#0087ff">self&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>.public_key = &lt;span style="color:#0087ff">self&lt;/span>.fetch_key()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">except&lt;/span> &lt;span style="color:#af8700">Exception&lt;/span> &lt;span style="color:#5f8700">as&lt;/span> exc:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.warning(&lt;span style="color:#00afaf">f&lt;/span>&lt;span style="color:#00afaf">&amp;#34;Could not update jwks public key: &lt;/span>&lt;span style="color:#00afaf">{&lt;/span>exc&lt;span style="color:#00afaf">}&lt;/span>&lt;span style="color:#00afaf">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">def&lt;/span> &lt;span style="color:#0087ff">fetch_key&lt;/span>(&lt;span style="color:#0087ff">self&lt;/span>) -&amp;gt; KeySet:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00afaf">&amp;#34;&amp;#34;&amp;#34;Fetch the jwks_uri document and return the KeySet.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> response = urlopen(&lt;span style="color:#0087ff">self&lt;/span>.jwks_uri)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> logger.debug(&lt;span style="color:#00afaf">f&lt;/span>&lt;span style="color:#00afaf">&amp;#34;OK GET &lt;/span>&lt;span style="color:#00afaf">{&lt;/span>&lt;span style="color:#0087ff">self&lt;/span>.jwks_uri&lt;span style="color:#00afaf">}&lt;/span>&lt;span style="color:#00afaf">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">return&lt;/span> JsonWebKey.import_key_set(json.loads(response.read()))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">def&lt;/span> &lt;span style="color:#0087ff">jwks_uri&lt;/span>(&lt;span style="color:#0087ff">self&lt;/span>) -&amp;gt; &lt;span style="color:#0087ff">str&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00afaf">&amp;#34;&amp;#34;&amp;#34;The jwks_uri field of the openid-configuration document.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">if&lt;/span> &lt;span style="color:#0087ff">self&lt;/span>._jwks_uri &lt;span style="color:#5f8700">is&lt;/span> &lt;span style="color:#d75f00">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> config_url = urlopen(&lt;span style="color:#00afaf">f&lt;/span>&lt;span style="color:#00afaf">&amp;#34;&lt;/span>&lt;span style="color:#00afaf">{&lt;/span>&lt;span style="color:#0087ff">self&lt;/span>._issuer&lt;span style="color:#00afaf">}&lt;/span>&lt;span style="color:#00afaf">/.well-known/openid-configuration&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> config = json.loads(config_url.read())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>._jwks_uri = config[&lt;span style="color:#00afaf">&amp;#34;jwks_uri&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">return&lt;/span> &lt;span style="color:#0087ff">self&lt;/span>._jwks_uri
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#5f8700">class&lt;/span> &lt;span style="color:#0087ff">BearerTokenAuthBackend&lt;/span>(AuthenticationBackend):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">def&lt;/span> __init__(&lt;span style="color:#0087ff">self&lt;/span>, issuer: &lt;span style="color:#0087ff">str&lt;/span>, audience: &lt;span style="color:#0087ff">str&lt;/span>) -&amp;gt; &lt;span style="color:#d75f00">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rp = ResourceProtector()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> validator = BearerTokenValidator(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> issuer=issuer,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> audience=audience,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rp.register_token_validator(validator)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0087ff">self&lt;/span>.resource_protector = rp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">async&lt;/span> &lt;span style="color:#5f8700">def&lt;/span> &lt;span style="color:#0087ff">authenticate&lt;/span>(&lt;span style="color:#0087ff">self&lt;/span>, conn: HTTPConnection):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> request = Request(conn.scope)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">try&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> token: JWTBearerToken = &lt;span style="color:#0087ff">self&lt;/span>.resource_protector.validate_request(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> scopes=[&lt;span style="color:#00afaf">&amp;#34;openid&amp;#34;&lt;/span>],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> request=request,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">except&lt;/span> (MissingAuthorizationError, OAuth2Error) &lt;span style="color:#5f8700">as&lt;/span> error:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">raise&lt;/span> AuthenticationError(error.description) &lt;span style="color:#d75f00">from&lt;/span> error
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> scope: &lt;span style="color:#0087ff">str&lt;/span> = token.get_scope()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> scopes = scope.split()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> scopes.append(&lt;span style="color:#00afaf">&amp;#34;authenticated&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#5f8700">return&lt;/span> AuthCredentials(scopes=scopes), SimpleUser(username=token[&lt;span style="color:#00afaf">&amp;#34;email&amp;#34;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>middleware = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Middleware(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> AuthenticationMiddleware,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> backend=BearerTokenAuthBackend(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> issuer=settings.oidc_issuer,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> audience=settings.oidc_audience,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Blog: New Puppet Service Offerings</title><link>http://openinfrastructure.co/blog/2023/02/23/new-puppet-service-offerings/</link><pubDate>Thu, 23 Feb 2023 12:00:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2023/02/23/new-puppet-service-offerings/</guid><description>
&lt;p>&lt;strong>TL;DR: Open Infrastructure Services (OIS) is proud to announce
&lt;a href="http://openinfrastructure.co/services/puppet/">several new Puppet service offerings&lt;/a> intended for customers of
varying size, from hundreds to millions of managed nodes.&lt;/strong>&lt;/p>
&lt;p>The commonality that unites the three of us at Open Infrastructure Services
(OIS) is the fact that at some point in time, we all were members of Puppet
Inc.&amp;rsquo;s Professional Services team. We were the engineers that were dispatched to
solve the most complex customer issues, and together we have more than 25 years
of experience in designing, customizing, and troubleshooting Puppet deployments.
It&amp;rsquo;s that experience that allows us to solve real world problems in a
predictable and timely manner, and we value our reputation of being able to
deliver for our customers.&lt;/p>
&lt;p>That&amp;rsquo;s why today we&amp;rsquo;re proud to announce &lt;a href="http://openinfrastructure.co/services/puppet/">several new Puppet service
offerings&lt;/a> available now to organizations of any size! While
it&amp;rsquo;s not an exhaustive list, it does comprise some of the most popular features
we&amp;rsquo;ve built in the past 6 years.&lt;/p>
&lt;h2 id="safer-puppet-changes">Safer Puppet Changes&lt;/h2>
&lt;p>Are Puppet changes causing incidents in your organization? Have you experienced
service outages due to a Puppet code change which rolls out too quickly to
control? Are you looking for a proven method to target a small group of
nodes for a risky change, validate the results, then safely release it to the
rest of your managed fleet?&lt;/p>
&lt;p>This is a problem all large Puppet deployments need to solve, and we recently
&lt;a href="http://openinfrastructure.co/services/puppet/incremental-rollouts/">designed a solution&lt;/a> for a large social media company that allowed them to
reduce Puppet-related incidents from at least one per-month, to zero reported
for more than an entire year.&lt;/p>
&lt;p>The existing tools to solve this problem are ineffective at the scale of
hundreds of thousands to millions of managed nodes. As a result, we developed a
new, effective solution which:&lt;/p>
&lt;ol>
&lt;li>Unlocks the ability to perform canary analysis on Puppet changes.&lt;/li>
&lt;li>Reduces engineering time by adding scheduling policies to risky changes.&lt;/li>
&lt;li>Leverages cloud native advancements in observability and traffic management.&lt;/li>
&lt;li>Uses the same workflows as are used for application level container rollouts.&lt;/li>
&lt;/ol>
&lt;p>We&amp;rsquo;d love to share how our solution reduces the risk of production changes.&lt;/p>
&lt;h2 id="advanced-reporting">Advanced Reporting&lt;/h2>
&lt;p>Does your organization struggle with these questions about production changes?&lt;/p>
&lt;ul>
&lt;li>When was a recent production change enforced on all managed nodes?&lt;/li>
&lt;li>Was the production change successful or were there failures?&lt;/li>
&lt;li>Was a recent Puppet change a contributing factor to a production incident?&lt;/li>
&lt;li>What are the most common resource failures across teams?&lt;/li>
&lt;li>Are nodes no longer being managed at all?&lt;/li>
&lt;/ul>
&lt;p>Many of these questions can be answered by the Puppet Enterprise Dashboard, but
what if your organization doesn&amp;rsquo;t use Puppet Enterprise or has outgrown Puppet
Enterprise? PuppetDB is open source and may help at smaller scales, but what if
the number of nodes in your organization exceeds PuppetDB&amp;rsquo;s limits?&lt;/p>
&lt;p>We recently built an advanced big data reporting solution using &lt;a href="https://cloud.google.com/bigquery">BigQuery&lt;/a>
and &lt;a href="https://datastudio.withgoogle.com/">Data Studio&lt;/a> to answer these questions. This solution worked
well in production, scaling to hundreds of thousands of managed nodes and
millions of Puppet run reports per day.&lt;/p>
&lt;p>We&amp;rsquo;re available to tailor a reporting solution to the needs of your
organization.&lt;/p>
&lt;h2 id="module-development">Module Development&lt;/h2>
&lt;p>The &lt;a href="https://forge.puppet.com/">Puppet Forge&lt;/a> has grown to contain thousands of Puppet modules
managing as many applications and technologies, but it never seems to have the
specific module that does what you need. And while the Puppet language (DSL) is
legible and approachable, it&amp;rsquo;s VERY easy for a &amp;ldquo;simple fix&amp;rdquo; to trigger a cascade
of unintended consequences.&lt;/p>
&lt;p>Wouldn&amp;rsquo;t it be great if you could explain what you need and have someone write
you a customized solution, conforming to best practices, complete with tests and
USABLE documentation?&lt;/p>
&lt;p>That&amp;rsquo;s exactly the kind of service we offer at OIS.&lt;/p>
&lt;p>The Puppet experts at OIS have been writing Puppet modules since 2009, and have
been following (and creating) best practices through to today. We literally
&lt;a href="http://www.amazon.com/Pro-Puppet-James-Turnbull/dp/1430230592">wrote the book on the subject&lt;/a>. Whether it&amp;rsquo;s writing a completely
new module from scratch, or adding new functionality to existing code, we are
here to help you work smarter, not harder.&lt;/p>
&lt;h2 id="open-source-puppet-support">Open Source Puppet Support&lt;/h2>
&lt;p>Free and open-source software (FOSS) is a bedrock principle at OIS - it puts the
&amp;ldquo;Open&amp;rdquo; in &amp;ldquo;Open Infrastructure!&amp;rdquo; We also understand that customers using the
FOSS version of Puppet have limited options when it comes to support plans. That&amp;rsquo;s
why we offer first class support for ALL Puppet users, regardless of whether you&amp;rsquo;re
using the Enterprise or FOSS editions. It doesn&amp;rsquo;t matter how old your code is or
what your server stack looks like, we are here to help.&lt;/p>
&lt;p>Whether you have a specific problem that needs a solution, or simply need the
ability to contact the experts when problems arise, we can craft a support plan
to fit your needs.&lt;/p>
&lt;hr>
&lt;p>As we said above, this is not an exhaustive list of every Puppet service we&amp;rsquo;re
able to offer. Do you have a problem that doesn&amp;rsquo;t fit neatly into one of the
offerings above? &lt;a href="http://openinfrastructure.co/contact/">Contact us and let&amp;rsquo;s start the conversation&lt;/a>. Our
most impactful engagements have started this way, and we&amp;rsquo;d be happy to discuss
your goals.&lt;/p></description></item><item><title>Blog: Welcome Nate McCurdy</title><link>http://openinfrastructure.co/blog/2018/12/03/welcome-nate-mccurdy/</link><pubDate>Mon, 03 Dec 2018 12:00:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2018/12/03/welcome-nate-mccurdy/</guid><description>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 210px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2018/12/03/welcome-nate-mccurdy/nate_hu6e56d896460733c160d57f5fa15e0289_13474_200x200_fit_q75_catmullrom.jpg" width="200" height="200">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Open Infrastructure Services is growing! I&amp;rsquo;m excited to announce &lt;a href="https://github.com/natemccurdy">Nate
McCurdy&lt;/a>, has joined Open Infrastructure Services as a Cloud
Infrastructure Consultant. Nate brings over a decade of experience helping
companies with their digital transformation, configuration management, and
breaking down walls between development and operations teams.&lt;/p>
&lt;p>Nate is also a &lt;a href="https://cloud.google.com/certification/cloud-architect">Google&lt;/a> certified Cloud Architect and helping streamline
large enterprise hybrid clouds to date.&lt;/p></description></item><item><title>Blog: Help Wanted</title><link>http://openinfrastructure.co/blog/2018/04/18/help-wanted/</link><pubDate>Wed, 18 Apr 2018 12:00:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2018/04/18/help-wanted/</guid><description>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 610px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2018/04/18/help-wanted/now-hiring_hub80781c1d79a5068a2b3589b9dd8f521_33061_600x600_fit_q75_catmullrom.jpg" width="600" height="337">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Open Infrastructure Services is hiring! We have a number of exciting projects
on the horizon and are looking for talented infrastructure engineers. If you&amp;rsquo;re
experienced with, or have an interest in cloud infrastructure automation and
helping customers migrate their data center workloads to the public cloud,
please send an email to &lt;a href="mailto://careers@openinfrastructure.co">careers@openinfrastructure.co&lt;/a>. We&amp;rsquo;d love to talk
to you about these exciting opportunities!&lt;/p>
&lt;p>These projects are focused on large enterprise datacenter migrations to the
Google Cloud.&lt;/p>
&lt;h1 id="apply-now">Apply Now&lt;/h1>
&lt;p>Apply online now: &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLScmmaD18PNg7H9UWqhfkgmqKYAA2AeWGSwjEt62JTRI8KOM5A/viewform?usp=sf_link">Employment Application&lt;/a>.&lt;/p>
&lt;iframe src="https://docs.google.com/forms/d/e/1FAIpQLScmmaD18PNg7H9UWqhfkgmqKYAA2AeWGSwjEt62JTRI8KOM5A/viewform?embedded=true" width="700" height="520" frameborder="0" marginheight="0" marginwidth="0">Loading...&lt;/iframe></description></item><item><title>Blog: Update ESXi 6.5 to U1 over SSH</title><link>http://openinfrastructure.co/blog/2017/11/22/update-esxi-6.5-to-u1-over-ssh/</link><pubDate>Wed, 22 Nov 2017 17:18:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2017/11/22/update-esxi-6.5-to-u1-over-ssh/</guid><description>
&lt;p>Updating ESXi 6.5 to 6.5 U1, I encountered the following error:&lt;/p>
&lt;pre tabindex="0">&lt;code>[root@esx:~] esxcli software profile update -d https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml -p ESXi-6.5.0-20170702001-standard
[InstallationError]
[Errno 28] No space left on device
vibs = VMware_locker_tools-light_6.5.0-0.23.5969300
Please refer to the log file for more details.
&lt;/code>&lt;/pre>&lt;p>The solution to this problem is to enable swap. I&amp;rsquo;m running this ESXi host on
a single 32GB USB Thumb Drive, so I first had to create a VMFS5 datastore using
the process at &lt;a href="http://openinfrastructure.co/news/esxi-single-usb-boot-plus-datastore/">ESXi 6.5 Single USB Thumb
Drive&lt;/a>.&lt;/p>
&lt;p>Once a datastore exists, enable Swap. Go to Host &amp;gt; System &amp;gt; Swap and activate
swap on your datastore of choice. In my case there&amp;rsquo;s only one.&lt;/p>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 810px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2017/11/22/update-esxi-6.5-to-u1-over-ssh/swap_hu95ddb8c366e87f3041a5bc6e091f731f_329680_800x0_resize_catmullrom_3.png" width="800" height="595">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Once activated, this process to update ESXi over SSH worked flawlessly:&lt;/p>
&lt;p>Enable outbound HTTP connections:&lt;/p>
&lt;pre>&lt;code>esxcli network firewall ruleset set -e true -r httpClient
&lt;/code>&lt;/pre>
&lt;p>Perform the update:&lt;/p>
&lt;pre>&lt;code>esxcli software profile update -d https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml -p ESXi-6.5.0-20170702001-standard
&lt;/code>&lt;/pre>
&lt;p>Lock down HTTP connections after the update:&lt;/p>
&lt;pre>&lt;code>esxcli network firewall ruleset set -e false -r httpClient
&lt;/code>&lt;/pre>
&lt;p>Reboot the host:&lt;/p>
&lt;pre>&lt;code>reboot
&lt;/code>&lt;/pre>
&lt;p>For future reference, to see a list of available updates, use&lt;/p>
&lt;pre>&lt;code>esxcli software sources profile list -d \
https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml \
| awk '/6.5.0/ {print $1}'
&lt;/code>&lt;/pre>
&lt;pre tabindex="0">&lt;code>[root@esx:~] esxcli software sources profile list -d https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml | awk &amp;#39;/6.5.0/ {print $1}&amp;#39;
ESXi-6.5.0-20170701001s-no-tools
ESXi-6.5.0-20170404001-standard
ESXi-6.5.0-4564106-standard
ESXi-6.5.0-20170104001-standard
ESXi-6.5.0-20171004001-no-tools
ESXi-6.5.0-20170702001-no-tools
ESXi-6.5.0-20170404001-no-tools
ESXi-6.5.0-20170304101-no-tools
ESXi-6.5.0-20171004001-standard
ESXi-6.5.0-20170104001-no-tools
ESXi-6.5.0-4564106-no-tools
ESXi-6.5.0-20170304101-standard
ESXi-6.5.0-20170301001s-standard
ESXi-6.5.0-20170701001s-standard
ESXi-6.5.0-20170304001-standard
ESXi-6.5.0-20170702001-standard
ESXi-6.5.0-20170304001-no-tools
ESXi-6.5.0-20170301001s-no-tools
&lt;/code>&lt;/pre></description></item><item><title>Blog: ESXi 6.5 Single USB Thumb Drive</title><link>http://openinfrastructure.co/blog/2017/11/22/esxi-6.5-single-usb-thumb-drive/</link><pubDate>Wed, 22 Nov 2017 15:06:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2017/11/22/esxi-6.5-single-usb-thumb-drive/</guid><description>
&lt;p>I have a goal of booting an ESXi host from a single 32GB USB thumb drive. No
other internal storage should be required for this firewall application. This
is an ideal setup as there are no moving parts or cables to come unplugged. USB
thumb drives are cheap and fast these days.&lt;/p>
&lt;p>I was able to install ESXi 6.5 onto the USB thumb drive, but nothing shows up as
an available data store for virtual machines. There&amp;rsquo;s a ton of free space on
the USB stick. We can make use of this space with some partitioning magic.&lt;/p>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 810px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2017/11/22/esxi-6.5-single-usb-thumb-drive/datastores_hudfcda79cf55823340af4513a2f2a6dcb_92706_800x0_resize_catmullrom_3.png" width="800" height="517">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>I&amp;rsquo;m doing this all with a Mac OS X workstation. I&amp;rsquo;ll use a Ubuntu 16.04
VirtualBox instance to partition the USB stick. We&amp;rsquo;ll format the filesystem on
the ESXi host itself.&lt;/p>
&lt;p>First install, ESX onto the USB stick.&lt;/p>
&lt;p>Shutdown the ESX host, remove the USB stick and insert into your Mac. Eject the
disk from your mac so it can be passed through VirtualBox to Ubuntu 16.04:&lt;/p>
&lt;pre>&lt;code>sudo diskutil list
sudo diskutil eject disk1
&lt;/code>&lt;/pre>
&lt;p>To quickly get a Ubuntu desktop up and running, use vagrant:&lt;/p>
&lt;pre>&lt;code>mkdir ~/xenial
cd ~/xenial
vagrant init ubuntu/xenial64
&lt;/code>&lt;/pre>
&lt;p>Patch the vagrant file to get the GUI:&lt;/p>
&lt;pre tabindex="0">&lt;code>--- Vagrantfile.orig 2017-11-22 16:03:04.000000000 -0800
+++ Vagrantfile 2017-11-22 16:04:49.000000000 -0800
@@ -57,4 +57,8 @@
# vb.memory = &amp;#34;1024&amp;#34;
# end
+ config.vm.provider &amp;#34;virtualbox&amp;#34; do |vb|
+ vb.gui = true
+ vb.memory = &amp;#34;2048&amp;#34;
+ end
#
# View the documentation for the provider you are using for more
&lt;/code>&lt;/pre>&lt;p>Bring up the vagrant instance:&lt;/p>
&lt;pre>&lt;code>vagrant up
&lt;/code>&lt;/pre>
&lt;p>Shutdown the instance and add USB to the virtual machine:&lt;/p>
&lt;pre>&lt;code>vagrant ssh -- sudo shutdown -h now
&lt;/code>&lt;/pre>
&lt;p>Go into VirtualBox Settings =&amp;gt; Ports =&amp;gt; Add a USB EHCI controller. Add a filter
for the USB thumb drive. This is important, otherwise the USB thumb drive won&amp;rsquo;t
show up in the Ubuntu VM. If the USB thub drive doesn&amp;rsquo;t show up in the GUI,
make sure it&amp;rsquo;s been ejected from Mac OS X using &lt;code>diskutil eject&lt;/code> prior to going
into VirtualBox settings.&lt;/p>
&lt;p>Install the Ubuntu Desktop:&lt;/p>
&lt;pre>&lt;code>vagrant ssh -- sudo apt-get install -y --no-install-recommends ubuntu-desktop
&lt;/code>&lt;/pre>
&lt;p>Install gparted&lt;/p>
&lt;pre>&lt;code>vagrant ssh -- sudo apt-get install -y gparted
&lt;/code>&lt;/pre>
&lt;p>Set a password for the user &lt;code>ubuntu&lt;/code>:&lt;/p>
&lt;pre>&lt;code>vagrant ssh -- sudo passwd ubuntu
&lt;/code>&lt;/pre>
&lt;p>Reboot again to get the desktop up and running.&lt;/p>
&lt;pre>&lt;code>vagrant ssh -- sudo shutdown -r now
&lt;/code>&lt;/pre>
&lt;p>Log in as ubuntu with the password just set. Open a terminal with &lt;code>ctrl&lt;/code> +
&lt;code>alt&lt;/code> + &lt;code>t&lt;/code>.&lt;/p>
&lt;p>Use &lt;code>sudo gparted&lt;/code> to create a new partition in the free space. Make sure to create
it as unformatted, not the default of ext4.&lt;/p>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 810px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2017/11/22/esxi-6.5-single-usb-thumb-drive/partition_hu96bc1105b72be28ab53077bc8623a3c1_192723_800x0_resize_catmullrom_3.png" width="800" height="548">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Note the partition number, it should be partition 2, e.g. &lt;code>/dev/sdc2&lt;/code>.&lt;/p>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 810px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2017/11/22/esxi-6.5-single-usb-thumb-drive/partitionnumber_hudde5a6c7f52a2b2a62c8975df73c8180_192098_800x0_resize_catmullrom_3.png" width="800" height="512">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Use &lt;code>sudo gdisk /dev/sdc&lt;/code> to change the partition type to &lt;code>fb00&lt;/code>. The sequence here is:&lt;/p>
&lt;ol>
&lt;li>&lt;code>t&lt;/code>&lt;/li>
&lt;li>&lt;code>2&lt;/code>&lt;/li>
&lt;li>&lt;code>fb00&lt;/code>&lt;/li>
&lt;li>&lt;code>w&lt;/code>&lt;/li>
&lt;li>&lt;code>Y&lt;/code>&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>vagrant ssh -- sudo gdisk /dev/sdc
GPT fdisk (gdisk) version 1.0.1
Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present
Found valid GPT with protective MBR; using GPT.
Command (? for help): t
Partition number (1-9): 2
Current type is &amp;#39;Linux filesystem&amp;#39;
Hex code or GUID (L to show codes, Enter = 8300): fb00
Changed type of partition to &amp;#39;VMWare VMFS&amp;#39;
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/sdc.
&lt;/code>&lt;/pre>&lt;p>Finally, change partition 2 to partition 10 to avoid issues updating ESXi 6.5.
The update process assumes partition 2 has not been created and will error out
if present.&lt;/p>
&lt;pre tabindex="0">&lt;code>sudo sfdisk -d /dev/sdc &amp;gt; esxi.txt
cp -p esxi.txt esxi.txt.orig
&lt;/code>&lt;/pre>&lt;p>Change &lt;code>esxi.txt&lt;/code> as the following diff shows, moving partition 2 to 10.&lt;/p>
&lt;pre tabindex="0">&lt;code>--- esxi.txt.orig 2017-11-23 00:13:57.561990531 +0000
+++ esxi.txt 2017-11-23 00:15:35.566968530 +0000
@@ -7,5 +7,4 @@
/dev/sdc1 : start= 64, size= 8128, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=439DBC97-6DB2-4FD1-BDEA-A01FC9F26A49
-/dev/sdc2 : start= 8134656, size= 51927040, type=AA31E02A-400F-11DB-9590-000C2911D1B8, uuid=7661DD41-6B25-4ACA-9A7E-E68F07361B9E
/dev/sdc5 : start= 8224, size= 511968, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=CC0591B2-6658-4A25-91CF-1A9765D239A5
/dev/sdc6 : start= 520224, size= 511968, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=CDD8851F-3A51-47AD-80E1-F2D504197A8C
@@ -13,2 +12,3 @@
/dev/sdc8 : start= 1257504, size= 585696, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=3119D6C6-3EEC-4970-9289-6128686849EB
/dev/sdc9 : start= 1843200, size= 5242880, type=9D275380-40AD-11DB-BF97-000C2911D1B8, uuid=7A6D08A3-6E3F-488D-8F3B-36145382BA9F
+/dev/sdc10 : start= 8134656, size= 51927040, type=AA31E02A-400F-11DB-9590-000C2911D1B8, uuid=7661DD41-6B25-4ACA-9A7E-E68F07361B9E
&lt;/code>&lt;/pre>&lt;p>Write the partition table back out to the USB drive:&lt;/p>
&lt;pre tabindex="0">&lt;code>sudo sfdisk --force /dev/sdc &amp;lt; esxi.txt
&lt;/code>&lt;/pre>&lt;p>Check the partition table, make sure there is a partition 10:&lt;/p>
&lt;pre tabindex="0">&lt;code>sudo fdisk -l /dev/sdc
&lt;/code>&lt;/pre>&lt;p>Insert the USB thumb drive back in the ESXi host and boot it back up. SSH in
as root and check the partition table. There should be no partition 2 and you
should see partition 10.&lt;/p>
&lt;pre tabindex="0">&lt;code>[root@esxi:~] partedUtil getptbl /dev/disks/mpx.vmhba32\:C0\:T0\:L0
gpt
3825 255 63 61457664
1 64 8191 C12A7328F81F11D2BA4B00A0C93EC93B systemPartition 128
5 8224 520191 EBD0A0A2B9E5443387C068B6B72699C7 linuxNative 0
6 520224 1032191 EBD0A0A2B9E5443387C068B6B72699C7 linuxNative 0
7 1032224 1257471 9D27538040AD11DBBF97000C2911D1B8 vmkDiagnostic 0
8 1257504 1843199 EBD0A0A2B9E5443387C068B6B72699C7 linuxNative 0
9 1843200 7086079 9D27538040AD11DBBF97000C2911D1B8 vmkDiagnostic 0
10 8134656 61456383 AA31E02A400F11DB9590000C2911D1B8 vmfs 0
&lt;/code>&lt;/pre>&lt;p>Format the partition with &lt;code>vmkfstools -C vmfs5 -S USB.1&lt;/code>:&lt;/p>
&lt;pre tabindex="0">&lt;code>[root@esxi:~] vmkfstools -C vmfs5 -S USB.1 /dev/disks/mpx.vmhba32\:C0\:T0\:L0:10
create fs deviceName:&amp;#39;/dev/disks/mpx.vmhba32:C0:T0:L0:10&amp;#39;, fsShortName:&amp;#39;vmfs5&amp;#39;, fsName:&amp;#39;USB.1&amp;#39;
deviceFullPath:/dev/disks/mpx.vmhba32:C0:T0:L0:10 deviceFile:mpx.vmhba32:C0:T0:L0:10
ATS on device /dev/disks/mpx.vmhba32:C0:T0:L0:10: not supported
.
Checking if remote hosts are using this device as a valid file system. This may take a few seconds...
Creating vmfs5 file system on &amp;#34;mpx.vmhba32:C0:T0:L0:10&amp;#34; with blockSize 1048576 and volume label &amp;#34;USB.1&amp;#34;.
Successfully created new volume: 5a1614ce-846cd3c8-9b10-0cc47aaaf624
&lt;/code>&lt;/pre>&lt;p>The partition now shows up in the datastore browser after a refresh.&lt;/p>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 810px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2017/11/22/esxi-6.5-single-usb-thumb-drive/populated_datastores_hudfcda79cf55823340af4513a2f2a6dcb_99321_800x0_resize_catmullrom_3.png" width="800" height="517">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Configure &lt;a href="https://labs.vmware.com/vmtj/vmware-esx-memory-resource-management-swap">swap&lt;/a>, a &lt;a href="https://kb.vmware.com/s/article/1033696">persistent scratch location&lt;/a>, and virtual machines
on the same USB drive ESX is booting from, and enjoy!&lt;/p></description></item><item><title>Blog: Welcome Gary Larizza</title><link>http://openinfrastructure.co/blog/2017/10/21/welcome-gary-larizza/</link><pubDate>Sat, 21 Oct 2017 12:06:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2017/10/21/welcome-gary-larizza/</guid><description>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 210px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2017/10/21/welcome-gary-larizza/gary_hu4cfa3877d419481add73dfa329fc874b_351250_200x200_fit_catmullrom_3.png" width="200" height="200">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>Open Infrastructure Services is growing! I&amp;rsquo;m excited to announce &lt;a href="http://garylarizza.com/">Gary
Larizza&lt;/a>, has joined Open Infrastructure Services as a Principal
Consultant. Gary and I first started working together on Puppet back in 2010 in
Portland, Oregon. From that first day working together I was struck by Gary&amp;rsquo;s
attitude and desire to dive deep in the guts of Puppet to figure out what&amp;rsquo;s
&lt;em>really&lt;/em> going on. Fast forward to 2017, and I&amp;rsquo;ve found myself visiting &lt;a href="http://garylarizza.com/blog/">Shit
Gary Says&lt;/a> on a daily basis while working on Puppet types and
providers. Gary&amp;rsquo;s ability to assimilate complex information, distill that
information into the essential bits customers value, and communicate that
essential information with humor and empathy has been invaluable to me
personally. A great example of this depth, humor, and empathy is, &lt;a href="http://garylarizza.com/blog/2013/12/15/seriously-what-is-this-provider-doing/">Seriously,
what is this provider doing?&lt;/a>&lt;/p>
&lt;p>Gary and I both started out working in education in Ohio, though separately from
one another. We were bought together in Portland, OR by two australians from
the other side of the world, Nigel Kersten and James Turnbull.&lt;/p>
&lt;p>Gary and I share that special bond that only comes from successfully dealing
with a classroom full of computers delivered a couple of weeks before school
starts with the latest and greatest Mac OS X major release, chock full of
changes and new surprises.&lt;/p>
&lt;p>Please check out Gary&amp;rsquo;s post, &lt;a href="http://garylarizza.com/blog/2017/08/25/some-other-beginnings-end/">Some Other Beginning&amp;rsquo;s End&lt;/a> on this new
beginning for both of us.&lt;/p>
&lt;p>&lt;a href="http://openinfrastructure.co/#contact">Contact&lt;/a> us with your automation and cloud infrastructure goals. We&amp;rsquo;d
both love to help you handle changes faster and more confidently through
automated cloud infrastructure.&lt;/p>
&lt;p>Gary is also a &lt;a href="https://puppet.com/product">Puppet&lt;/a> certified consultant and a member of the Puppet
Services Delivery Partner Program. We&amp;rsquo;re here to help achieve your goals
whether you&amp;rsquo;re expanding your Puppet investment, upgrading to the latest version
and language features, or just getting started.&lt;/p></description></item><item><title>Blog: Puppet Enterprise Node Classification Backup &amp; Restore with ncio</title><link>http://openinfrastructure.co/blog/2016/08/21/puppet-enterprise-node-classification-backup-restore-with-ncio/</link><pubDate>Sun, 21 Aug 2016 12:48:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2016/08/21/puppet-enterprise-node-classification-backup-restore-with-ncio/</guid><description>
&lt;p>I&amp;rsquo;m happy to announce &lt;a href="https://github.com/jeffmccune/ncio">ncio&lt;/a>, a small command line utility to backup and
restore Puppet Enterprise Node Classification data.&lt;/p>
&lt;p>A customer recently needed to automate the process of backing up and restoring
&lt;a href="https://puppet.com/product">Puppet Enterprise&lt;/a>. Most of the work involved in accomplishing this
goal is fairly straight-forward. The majority of the Puppet configuration is
stored in version control in a &lt;a href="https://github.com/puppetlabs/control-repo">Control Repository&lt;/a> and Git is
incredibly easy to backup and restore. Most customers I work with don&amp;rsquo;t mind
losing data stored in PuppetDB because Puppet reports, resource information,
and facts are automatically re-populated as nodes check in after the system is
restored. The certificates used by Puppet are also fairly straight forward to
backup as they live on the local filesystem.&lt;/p>
&lt;p>The only service that was difficult to backup using normal filesystem tools is
the Node Classification Service. The node classifier stores critical
information and as a result it needs to be backed up and restored along side
all of these other resources.&lt;/p>
&lt;p>The &lt;a href="https://docs.puppet.com/pe/2016.2/nc_index.html">Node classification v1 API&lt;/a> is an excellent mechanism to retrieve
and restore node classification data, but the task of using the API is largely
left as an exercise for the reader. In order to help with this common problem,
I wrote a small utility called ncio (node classification input / ouput). If
you&amp;rsquo;d like to easily get a dump of all node classification data in
pretty-printed JSON, transform a backup for restoration on a different PE
Monolithic Master, or restore a backup then this tool is for you.&lt;/p>
&lt;p>The tool is distributed and updated on &lt;a href="https://rubygems.org/gems/ncio/">rubygems&lt;/a> in an effort to make
it easiy to install and upgrade in the future.&lt;/p>
&lt;p>Here&amp;rsquo;s how to get started:&lt;/p>
&lt;h1 id="installation">Installation&lt;/h1>
&lt;p>Installation is straight-forward thanks to Puppet Enterprise shipping with the
gem command:&lt;/p>
&lt;pre>&lt;code>$ sudo /opt/puppetlabs/puppet/bin/gem install ncio
Successfully installed ncio-1.1.0
Parsing documentation for ncio-1.1.0
Installing ri documentation for ncio-1.1.0
Done installing documentation for ncio after 0 seconds
1 gem installed
&lt;/code>&lt;/pre>
&lt;h1 id="usage">Usage&lt;/h1>
&lt;p>The command runs best from a PE Monolithic Master. The tool automatically uses
SSL certificates which are already present to make setup as easy as possible.&lt;/p>
&lt;pre>&lt;code>sudo -H -u pe-puppet /opt/puppetlabs/puppet/bin/ncio backup &amp;gt; /var/tmp/backup.json
I, [2016-06-28T19:25:55.507684 #2992] INFO -- : Backup completed successfully!
&lt;/code>&lt;/pre>
&lt;h2 id="retrying-connections">Retrying Connections&lt;/h2>
&lt;p>When automating a backup from cron, it&amp;rsquo;s recommended to use the
&lt;code>--retry-connections&lt;/code> global option to make the backup as robust as possible.
This option allows &lt;code>ncio&lt;/code> to retry in certain situations, e.g. when the
puppetserver service is restarting.&lt;/p>
&lt;h2 id="restore-pipelines">Restore Pipelines&lt;/h2>
&lt;p>The command is designed to send a backup to standard output and restore from
standard input. This allows backup and restore pipelines. In this example a
backup is taken on &lt;code>master1&lt;/code>, transformed so that it can be restored on
&lt;code>master2&lt;/code>, then restored on &lt;code>master2&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0087ff">export&lt;/span> &lt;span style="color:#0087ff">PATH&lt;/span>=&lt;span style="color:#00afaf">&amp;#34;/opt/pupeptlabs/puppet/bin:&lt;/span>&lt;span style="color:#0087ff">$PATH&lt;/span>&lt;span style="color:#00afaf">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ncio --uri https://master1.puppet.vm:4433/classification-api/v1 backup &lt;span style="color:#af0000">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#af0000">&lt;/span> | ncio transform --hostname master1.puppet.vm:master2.puppet.vm &lt;span style="color:#af0000">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#af0000">&lt;/span> | ncio --uri https://master2.puppet.vm:4433/classification-api/v1 restore
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h1 id="command-overview">Command overview&lt;/h1>
&lt;p>Global options:&lt;/p>
&lt;pre tabindex="0">&lt;code>$ ncio --help
usage: ncio [GLOBAL OPTIONS] SUBCOMMAND [ARGS]
Sub Commands:
backup Backup Node Classification resources
restore Restore Node Classification resources
transform Transform a backup, replacing hostnames
Quick Start: On the host of the Node Classifier service, as root or pe-puppet
(to read certs and keys)
/opt/puppetlabs/puppet/bin/ncio backup &amp;gt; groups.$(date +%s).json
/opt/puppetlabs/puppet/bin/ncio restore &amp;lt; groups.1467151827.json
Transformation:
ncio --uri https://master1.puppet.vm:4433/classification-api/v1 backup \
| ncio transform --hostname master1.puppet.vm:master2.puppet.vm \
| ncio --uri https://master2.puppet.vm:4433/classification-api/v1 restore
Global options: (Note, command line arguments supersede ENV vars in {}&amp;#39;s)
-u, --uri=&amp;lt;s&amp;gt; Node Classifier service uri {NCIO_URI}
(default: https://localhost:4433/classifier-api/v1)
-c, --cert=&amp;lt;s&amp;gt; White listed client SSL cert {NCIO_CERT}
See: https://goo.gl/zCjncC (default:
/etc/puppetlabs/puppet/ssl/certs/pe-internal-orchestrator.pem)
-k, --key=&amp;lt;s&amp;gt; Client RSA key, must match certificate {NCIO_KEY} (default:
/etc/puppetlabs/puppet/ssl/private_keys/pe-internal-orchestrator.pem)
-a, --cacert=&amp;lt;s&amp;gt; CA Cert to authenticate the service uri {NCIO_CACERT}
(default: /etc/puppetlabs/puppet/ssl/certs/ca.pem)
-l, --logto=&amp;lt;s&amp;gt; Log file to write to or keywords STDOUT,
STDERR {NCIO_LOGTO} (default: STDERR)
-s, --syslog, --no-syslog Log to syslog (default: true)
-v, --verbose Set log level to INFO
-d, --debug Set log level to DEBUG
-r, --retry-connections Retry API connections, e.g. waiting for the
service to come online. {NCIO_RETRY_CONNECTIONS}
-o, --connect-timeout=&amp;lt;i&amp;gt; Retry &amp;lt;i&amp;gt; seconds if --retry-connections=true
{NCIO_CONNECT_TIMEOUT} (default: 120)
-e, --version Print version and exit
-h, --help Show this message
&lt;/code>&lt;/pre>&lt;h2 id="backup-options">Backup options&lt;/h2>
&lt;pre tabindex="0">&lt;code>$ ncio backup --help
Node Classification backup options:
-g, --groups, --no-groups Operate against NC groups. See: https://goo.gl/QD6ZdW (default: true)
-f, --file=&amp;lt;s&amp;gt; File to operate against {NCIO_FILE} or STDOUT, STDERR (default: STDOUT)
-h, --help Show this message
&lt;/code>&lt;/pre>&lt;h2 id="transform-options">Transform options&lt;/h2>
&lt;pre tabindex="0">&lt;code>$ ncio transform --help
Node Classification transformations
Note: Currently only Monolithic (All-in-one) deployments are supported.
Transformation matches against class names assigned to groups. Transformation
of hostnames happen against rules assigned to groups and class parameters for
matching classes.
Options:
-c, --class-matcher=&amp;lt;s&amp;gt; Regexp matching classes assigned to groups.
Passed to Regexp.new() (default: ^puppet_enterprise)
-i, --input=&amp;lt;s&amp;gt; Input file path or keywords STDIN, STDOUT, STDERR (default: STDIN)
-o, --output=&amp;lt;s&amp;gt; Output file path or keywords STDIN, STDOUT, STDERR (default: STDOUT)
-h, --hostname=&amp;lt;s+&amp;gt; Replace the fully qualified domain name on the left with the
right, separated with a :
e.g --hostname master1.acme.com:master2.acme.com
-e, --help Show this message
&lt;/code>&lt;/pre>&lt;h2 id="restore-options">Restore options&lt;/h2>
&lt;pre tabindex="0">&lt;code>$ ncio restore --help
Node Classification restore options:
-g, --groups, --no-groups Operate against NC groups.
See: https://goo.gl/QD6ZdW (default: true)
-f, --file=&amp;lt;s&amp;gt; File to operate against {NCIO_FILE} or STDOUT,
STDERR (default: STDIN)
-h, --help Show this message
&lt;/code>&lt;/pre>&lt;p>Hopefully you find &lt;a href="https://github.com/jeffmccune/ncio">ncio&lt;/a> useful. If so, please let me know! If you run
into any issues or would like to see additional features, please open up an
issue on the project page.&lt;/p></description></item><item><title>Blog: Logo</title><link>http://openinfrastructure.co/blog/2016/02/27/logo/</link><pubDate>Sat, 27 Feb 2016 17:53:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2016/02/27/logo/</guid><description>
&lt;p>Finally got a logo. It turned out to be pretty easy once I finally took the
plunge and signed up for &lt;a href="https://www.fiverr.com/">fiverr&lt;/a>. Fairly inexpensive, and a quick 5
day turnaround on the design. I was able to take the original image files and
work with them in &lt;a href="https://www.gimp.org/">The GNU Image Manipulation Program&lt;/a>.&lt;/p>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 810px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2016/02/27/logo/logorectangle_hu9034d9ce96576fd3c018884bb416f222_24000_800x0_resize_catmullrom_3.png" width="800" height="441">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure></description></item><item><title>Blog: Lift Off!</title><link>http://openinfrastructure.co/blog/2015/10/06/lift-off/</link><pubDate>Tue, 06 Oct 2015 13:39:00 +0000</pubDate><guid>http://openinfrastructure.co/blog/2015/10/06/lift-off/</guid><description>
&lt;h2 id="3-2-1-lift-off">3.. 2.. 1.. Lift Off!&lt;/h2>
&lt;a href="https://www.flickr.com/photos/spacexphotos/16698990175/in/photostream/" target="_blank">
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 810px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2015/10/06/lift-off/liftoff_hu9d537ff6a2081e53e89e631d49a77a2f_342072_800x0_resize_q75_catmullrom.jpg" width="800" height="272">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/a>
&lt;p>I&amp;rsquo;m pleased to announce Open Infrastructure Services, LLC is open for business!
Here&amp;rsquo;s some information about myself and the services I have available. Please
&lt;a href="mailto://jeff@openinfrastructure.co">email&lt;/a> me with any questions about how I can help.&lt;/p>
&lt;p>Open Infrastructure Services is founded by me, &lt;a href="https://about.me/jeffmccune">Jeff McCune&lt;/a>, a veteran
systems administrator and software developer with over 15 years of experience.
Before starting my consulting business I was at &lt;a href="https://puppetlabs.com">Puppet Labs&lt;/a> as a software
developer working on &lt;a href="http://github.com/puppetlabs/puppet">Puppet&lt;/a>, &lt;a href="http://github.com/puppetlabs/facter">Facter&lt;/a>, &lt;a href="http://github.com/puppetlabs/puppet-server">Puppet
Server&lt;/a>, and other internal tools like
&lt;a href="https://github.com/puppetlabs/crossfader">crossfader&lt;/a>. Prior to that, I was a
professional services engineer at Puppet Labs, traveling the world working with
customers and the open source community on matters of system architecture,
availability, security, and continuous delivery workflows.&lt;/p>
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 210px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2015/10/06/lift-off/jeff_hu47c47feda2209c085de64f836cfba2e6_13454_200x0_resize_q75_catmullrom.jpeg" width="200" height="200">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;p>While traveling for Puppet Labs, I also co-authored &lt;a href="http://www.amazon.com/Pro-Puppet-James-Turnbull/dp/1430230592">Pro Puppet&lt;/a>, the
best-selling book about how to quickly get started and then scale Puppet toward
full automation.&lt;/p>
&lt;a href="http://www.amazon.com/Pro-Puppet-James-Turnbull/dp/1430230592" target="_blank">
&lt;figure class="card rounded p-2 td-post-card mb-4 mt-4" style="max-width: 210px">
&lt;img class="card-img-top" src="http://openinfrastructure.co/blog/2015/10/06/lift-off/propuppet_hu41be82a4f19a635ca6fcc30b8e1ff366_42286_200x0_resize_q75_catmullrom.jpg" width="200" height="246">
&lt;figcaption class="card-body px-0 pt-2 pb-0">
&lt;p class="card-text">
&lt;/p>
&lt;/figcaption>
&lt;/figure>
&lt;/a>
&lt;p>Before Puppet Labs I worked at &lt;a href="http://www.ntst.com">Netsmart Technologies&lt;/a> where I was
responsible for our hosted SaaS datacenters. Puppet and DevOps practices
played a key part of my success at Netsmart. We were able to implement SAS-70
II compliance in a matter of months using a well defined change management
process, and detailed automated reports integrated with Puppet and &lt;a href="http://www.splunk.com">Splunk&lt;/a>.&lt;/p>
&lt;p>Prior to Netsmart Technologies, I worked at the Mathematics Department at Ohio
State University. There, I learned about automation, &lt;a href="http://cfengine.com/">cfengine&lt;/a>,
started using &lt;a href="http://github.com/puppetlabs/puppet">Puppet&lt;/a>, and fully automated our Mac OS X workstations
and labs. In order to achieve full automation for PowerPC and Intel based
systems, I reverse engineered Apple&amp;rsquo;s boot service discovery protocol and
patched ISC DHCP to behave as an automated network boot server for Mac OS X. I
presented on Puppet at Apple&amp;rsquo;s Worldwide Developer Conference.&lt;/p>
&lt;p>Please &lt;a href="http://openinfrastructure.co/contact/">contact me&lt;/a> if you have a need for professional, intelligent
and creative solutions to the infrastructure problems that are holding you back
from delivering your applications.&lt;/p></description></item><item><title>Blog: Announcing Open Infrastructure Services, LLC</title><link>http://openinfrastructure.co/blog/2015/09/20/announcing-open-infrastructure-services-llc/</link><pubDate>Sun, 20 Sep 2015 18:33:10 +0000</pubDate><guid>http://openinfrastructure.co/blog/2015/09/20/announcing-open-infrastructure-services-llc/</guid><description>
&lt;p>Hello, World!&lt;/p>
&lt;p>I&amp;rsquo;m a little sad to say I&amp;rsquo;ve left &lt;a href="http://puppetlabs.com">Puppet Labs&lt;/a> after over 5 years
working for the company and working on &lt;a href="http://github.com/puppetlabs/puppet">Puppet&lt;/a>. It was a difficult
decision, but I&amp;rsquo;m pleased to announce that I&amp;rsquo;ve decided to start my own
independent consulting business, &lt;a href="http://openinfrastructure.co">Open Infrastructure Services, LLC&lt;/a>.
I&amp;rsquo;ll be helping clients with their Puppet related problem while also focusing
on bringing creative solutions to bear on complex infrastructures. Please
&lt;a href="mailto://jeff@openinfrastructure.co">email me&lt;/a> for more information, I&amp;rsquo;d love to hear how I could help you
and your business.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#8a8a8a;background-color:#1c1c1c;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-puppet" data-lang="puppet">&lt;span style="display:flex;">&lt;span>company { &lt;span style="color:#00afaf">&amp;#34;Open Infrastructure Services, LLC&amp;#34;&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ensure =&amp;gt; &lt;span style="color:#5f8700">running&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> founder =&amp;gt; &lt;span style="color:#00afaf">&amp;#34;Jeff McCune&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> website =&amp;gt; &lt;span style="color:#00afaf">&amp;#34;http://openinfrastructure.co&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> email =&amp;gt; &lt;span style="color:#00afaf">&amp;#34;jeff@openinfrastructure.co&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item></channel></rss>