tag:blogger.com,1999:blog-28707138657529556872024-03-12T17:26:02.751-07:00Hey Stephen WoodExplore nerdy things with me.Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.comBlogger54125tag:blogger.com,1999:blog-2870713865752955687.post-36508975538529662302020-10-27T22:06:00.010-07:002020-10-28T10:36:14.301-07:00The curious case of Python's datetime -0753 UTC offset<p></p><h3 style="text-align: left;"><span style="font-weight: normal;"> <span color="var(--color-text-tertiary)" face="-apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"" style="background-color: white; font-size: 14px;">"Time, the devourer of all things." - Ovid's Metamorphoses</span></span></h3><span color="var(--color-text-tertiary)" face="-apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"" style="background-color: white; font-size: 14px;"></span><p></p><p style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 16px; margin-top: 0px;">Confused why your python datetime object's UTC offset is showing up as <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">-0753</code> instead of <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">-0700</code> (PDT) or <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">-0800</code> (PST)? I certainly was.</p><p style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 16px; margin-top: 0px;">The tl;dr is because Python's <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">pytz</code> does not do the right thing with daylight saving's time when simply adding a timezone to a naive datetime object, and you must localize it.</p><p style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 16px; margin-top: 0px;">Here's an example of what I was encountering. I was parsing a timestamp which was in the <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">America/Los_Angeles</code> timezone. I needed to change the printed format, so I parsed the date and did a quick strftime and... <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">-0753</code>??</p><div class="highlight highlight-source-python" style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 16px; overflow: visible;"><pre style="background-color: var(--color-bg-tertiary); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">from</span> <span class="pl-s1" style="box-sizing: border-box;">datetime</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">import</span> <span class="pl-s1" style="box-sizing: border-box;">datetime</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">import</span> <span class="pl-s1" style="box-sizing: border-box;">pytz</span>
<span class="pl-s1" style="box-sizing: border-box;">tz</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s1" style="box-sizing: border-box;">pytz</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">timezone</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;">"America/Los_Angeles"</span>)
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"># Super duper sure this is America/Los_Angeles tz</span>
<span class="pl-s1" style="box-sizing: border-box;">niave_string</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s" style="box-sizing: border-box; color: #032f62;">"2020-10-05 14:03:40"</span>
<span class="pl-s1" style="box-sizing: border-box;">dateobj</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s1" style="box-sizing: border-box;">datetime</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">strptime</span>(<span class="pl-s1" style="box-sizing: border-box;">niave_string</span>, <span class="pl-s" style="box-sizing: border-box; color: #032f62;">"%Y-%m-%d %H:%M:%S"</span>)
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"># Make it a timezone-aware object (Or so you think)</span>
<span class="pl-s1" style="box-sizing: border-box;">dateobj</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s1" style="box-sizing: border-box;">dateobj</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">replace</span>(<span class="pl-s1" style="box-sizing: border-box;">tzinfo</span><span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span><span class="pl-s1" style="box-sizing: border-box;">tz</span>)
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"># Notice the -0753 UTC offset...</span>
<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">print</span>(<span class="pl-s1" style="box-sizing: border-box;">dateobj</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">strftime</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;">"%Y-%m-%d %H:%M:%S%z"</span>))
<span class="pl-s" style="box-sizing: border-box; color: #032f62;">'2020-10-05 14:03:40-0753'</span></pre></div><p style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 16px; margin-top: 0px;">The mismatch happens because you can't just slap a tz onto a naive datetime object and hope it will do the right thing. More info on what's happening here can be found on this great <a href="https://stackoverflow.com/questions/56081666/what-does-753-mean-in-terms-of-timezone-in-pd-timestamp" rel="nofollow" style="background-color: initial; box-sizing: border-box; text-decoration-line: none;">stack overflow answer</a>.</p><p style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 16px; margin-top: 0px;">The fix for this is to <em style="box-sizing: border-box;">localize</em> your date objects, not just replace the TZ:</p><div class="highlight highlight-source-python" style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 16px; overflow: visible;"><pre style="background-color: var(--color-bg-tertiary); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">from</span> <span class="pl-s1" style="box-sizing: border-box;">datetime</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">import</span> <span class="pl-s1" style="box-sizing: border-box;">datetime</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">import</span> <span class="pl-s1" style="box-sizing: border-box;">pytz</span>
<span class="pl-s1" style="box-sizing: border-box;">tz</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s1" style="box-sizing: border-box;">pytz</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">timezone</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;">"America/Los_Angeles"</span>)
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"># Super duper sure this is America/Los_Angeles tz</span>
<span class="pl-s1" style="box-sizing: border-box;">niave_string</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s" style="box-sizing: border-box; color: #032f62;">"2020-10-05 14:03:40"</span>
<span class="pl-s1" style="box-sizing: border-box;">dateobj</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s1" style="box-sizing: border-box;">datetime</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">strptime</span>(<span class="pl-s1" style="box-sizing: border-box;">niave_string</span>, <span class="pl-s" style="box-sizing: border-box; color: #032f62;">"%Y-%m-%d %H:%M:%S"</span>)
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"># Localize your date object to your timezone</span>
<span class="pl-s1" style="box-sizing: border-box;">dateobj</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">=</span> <span class="pl-s1" style="box-sizing: border-box;">tz</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">localize</span>(<span class="pl-s1" style="box-sizing: border-box;">dateobj</span>)
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"># 🤞🏻</span>
<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">print</span>(<span class="pl-s1" style="box-sizing: border-box;">dateobj</span>.<span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">strftime</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;">"%Y-%m-%d %H:%M:%S%z"</span>))
<span class="pl-s" style="box-sizing: border-box; color: #032f62;">'2020-10-05 14:03:40-0700'</span></pre></div><p style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin-bottom: 0px; margin-top: 0px;">Much better.</p>Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-73294236657253588952020-08-11T11:26:00.008-07:002020-08-11T15:58:28.180-07:00GP, BD, SB, and other satellite annotations in cgps/xgps gpsd service<p>Sometimes I stumble onto a problem and Google really has no idea what I'm asking about.</p><p>In my case it's the 2-letter satellite code in the CGPS/XGPS program. What are these 2-letter symbols and what do they represent? They are different satellite-based radionavigation (<a href="https://en.wikipedia.org/wiki/Radionavigation-satellite_service">RNSS</a>) identification codes.</p><p></p><p>Below is the output from cgps, a terminal GUI for the gpsd software I currently have running on my stratum-1 raspberry pi NTP timeserver:</p><p><img alt="Not my real GPS coordinates :-)" height="325" src="data:image/png;base64,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CzFIl5lb9zj48DHpsWG3dHAdmzHfA3cF183bCaeVTy3eX3HFFbay3XfffYmNAR0bdMIJJyTypcXZx58oHmZinnjiCRsH/lxwPXDgQOt+0003BXE7/fTTrdunn35qzaLQAkLLly83bdq0sXznnXeedeOvffv2ppY8afnEexdcv/jii0HaFABExsEAACAASURBVFwXu95mAaZx4Hry5MlWNufNmxd7fLGAa+oG8tK6dWuD1gyqtJ5mSYOPLGfhAVwze5blmyLwJrVRUfHzbXujvq2VG2XBzAnaaSgKXGOO58YHbS/03XffxSr24I9q511/mvveJ+3jxo2zaT355JNtHmyyySb2mQFHc8c/LnzJ92nTptk4XnnllTbOuMd908S9HsF1hw4dzJAhQ8wrr7xi3n77bUOnOnfuXLPOOuvY6RXOjL/mmmtsZqCZ5pkfmg4yYI011rAVgOlEfmSYOzUOD9M0af5gcsL3aEzcjB02bJiZM2eObcjFnRHQgAEDzPPPP2+WLFli48afaxay3377menTp1sNI9pSNKDEVfyQK/7TsLoaR3mn1/xBxdSpU215ocWOy9/evXtbHmRJOvI43iR3H3/ieMR9wYIFNi7PPvtsEF8aCQjTEAl/o402sm78YV992WWX2WeZ9sKO1TUjufTSS2vKI/FMurrgmsgfddRRNn0KrvOvB0nlkPVdFmAaB66ZVodYQxAXfhhcw8fMDUQfEvedj3uWNPj4l4WnXsF1UhsVlX6ftjfqu1q6MUjbfPPNrekcchUFrsPxOf74460Mum10mEfyqtI+Jexvns8+aWddG/Tggw+a1VZbzWrveX7yyScrqn95piPsFyYrmIBAxxxzTDAzwZqOMG/sc72BaxaXSaOKhm3RokVWfU8mAHalU7W5EvqTkT4LCZiOoYESCi9o9PGnY8eO9nPsVt0MZroDYioed65MQ0JMzRO22F8JuKaDWLlypeVZunSpBc883HbbbSV+4x8jPgg/3XD1Pj9AQaPB4OX111+3ef3ee+8FU83hfN5pp51seTLlzJRn+L3vs48/cTwM3pia/OqrryzYINJuw820ONSjR48gft26dbNu/KFVwC4OYvBGnMeOHWufqTfQyJEja8rjk28CrpctW2bjyMCCgbLUXzULya9O+JSHL08WYBoFrkXz99lnnwXyHBV2FLhm8AjRaUZ94+uW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nxsPKKSVaZJsMIWLfB199NFW9l15F38xl2KhI/vy0hH5moLI977XrPXL11/la3kyn1bmeYFrCQdgxhoCDgZj7Y24V/OaJQ3ViAftADtQsEBftrKrRjh5+0m8WazNNrvhg90Iq97S5ds+gzW22247c9RRR9lrNQZ8eZeV+ldB210kcJ1WkNL5uwuu0r7R9xUIR41WkmsZFaOMtH4VoxxaQn3IAkzjbK6bO5+ypKG546rha91WGaixDNQTuEarDSm4rrGQKMiuiSasuRs/rV9ar2olg1mAqYJrlctayaWGo7KWmwzUE7jGbASbsyIf85pbwSigbRGAtkjyovVLO5ZayaOCa5W1WsmahqOy1iwyUE/gulkySEGuglyVAZUBlYFcZUDBtQIe7c9VBhpaBvIG17IdWUNnmna0uXa0KivayKoMtCwZyAKui9qnZEmDynfLkm8tby3vViFwfevtcwy/EnfBkthkpglNUe3j0uKt77UyqAyoDKgM1EYGsgDTovYpWdKgclUbudJ81nwujAyEwPXvBt9j+Cm4lhGFXlMHVIURZi0rLSuVgbqQgSzAVMG1AibtY1QG6k4GFFz/W2jZS7hv375N9qpmA3FOz+Moz7orYAUbuZUZh67IgQcqB/+uN5oXmhdZZSBvcM0+1xwmtuuuu6aeSZA1rnH8WdIQ50ec+1prrWV23313e94DV57DvOyvvNtuu9m9rjfccMMm78P8RXjmJMYDDzzQtqPbbLNNbJw5V4K2lrSnnWdRhHQ1annlmbf1VqYVp70o4JoKx8lUo0ePLqlwHF+OO+8rTmwK0Lz99tvtVn/s9ythsdH7559/bt332GOPwF3e67VlAIt9993XyoCewNkyylvrdXXLOQswTdJcc0IjR59zQqHQN998E5yg+8knn9j+gz6EE+84EfChhx4yHMtcaRlnSUOWsDjCXE4GljT97W9/syerij9du3Y1pM2lO+64w6y66qoVp0vCyPsqR9W7ceZYcPeANuLPce6kV+jjjz+2B23lHZ+8/MujvMgDThJFTqN+rDvIK755+8MhfY888oiNNydmh/2vtzJ9+OGHbVpGjBhRkpYzzzzTuvM+nMbI56KAa05lhAC4bkTZ0xrivetejfsocE04Z511lhk+fHihj5atRn6on/8CGBzb+9prr9mKxWmKmi/VBV6av42fv1mAaRy45jTc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TvUT92pes6Qh73hgNkHfdfTRR9t+ztc2O+94ZPGPkww54Ib9xVFQYQoS9T3azj333NPyderUqSH6wnosr6iyKdetEcs0NS/qFVynJswB4s3Jywp2prpY0U2jctxxx9kTIRkNMXXSnHHTsOsDiGg5aTk1mgxkAaZxNtfNnSdZ0tDccdXwtQ1RGaixDCi4rm6Go4V+88037dSC/DGFiT0dI3kV+Ormv+av5q/KQPFkIAswVXBdvPLTOqVlojKQIgMKrlMyKCcNODZn2HszdenamKmA1ib/NZ81n1UGiiMDCq6LUxZaL7QsVAaqIAMKrquQqTkBchV4LRuVAZWBRpQBBdcq140o15omletABvIG17INSxCAAk01/VAZUBlQGVAZcGQgC7guap+SJQ3aHyroUhloYTIQAte33j7H8GvlukubyO4baQJSVPu4tHjr+xYm+CLUek2t01o3tG7kLQNZgGlR+5Qsacg7/9Q/rZMqAwWXARdEr9nd/G7wPfan4FpBl4IulQGVAZWBqshAFmCq4LrgIELrSFXqiILnOpf7ooJr9i099NBDza677hrsQ81xsH379g1+p556aqJQs/E3p1ex13RWQWWfacJiX86s3yp/nVeKDJ3FVlttZWWkXbt2FcmJjz8+PL6yx0mUbPJ/xx13GI57/81vflNR/Al3//33t/vX+sZB+Cqpp+KHXuurzim4rry82G1qt912s6cOF/H0wqg6yX7HHInNwSJceY7ia1Q3nzbch6dI+eNbpquuuqrhyHvKnpOp11xzzcYu+6KBa07c4ihbOWGR7eu++eYbe2DM8ccfL7vZ2SunL8YJGYfMyFGqe+yxRyxf3Pec8AXddtttmb+N81PdK+9QipKH6667rnnhhRdK5JFn3LPE0ccfH54sYR5xxBFNTrR77LHHgnhzOBOnmrLDja+/++67r82LrCeLVlpPfeOnfMWqe3mAa9p3TjPkx+l/nNR7zTXXGDpxypsTWelHhOeLL74wCxYssMdq5yEPWdIQFV7Pnj1t3P7whz80qWccjvbII4/Y948++miT9127djWffPJJSfvDQFnSHhVec7vdddddwanIEnFOXzzggANs+jjMjdM0pbzC1yKfC5FWXj5tuA9Pc5dhOPy0MhV+ADVl7dJf/vKXJnIt/M15ffjhh60MjhgxoiR+Z555pnXnvVf8igSu0Ra/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bfIOc+dJWQOo//u//1tZZ65Yw0z6C8+NedSX5OECnF389CWZhbT23foS8r6L8r4u4JpNK4sXLzY/WbR76623YrfkJskxY8ZE06dPb8pKX5kFFFABAVS08YbrySefXHsQAZ/QRx99FF100UUR5o+RDe5FeYHpcQgT6TfeeGOEmWYReSMZ33///cZ52bJl0dixY6Ply5ebZ9zl55NPPjFu8+bNM8BPA6d3333XAGv8wRs8rlixwviFR30frm4Nzi9+8Yvo008/NfLj78EHH2xJhpxRrbx79NFHG8IaPny4MaKDIZ1LLrkkOuGEE6Jrr702WrBgQYO/kHduedercnIBzi5+elU+IV19u36E/O/i/K8LuLYLEbOf0BlnnFH7jljgescdd6w9r7aMAcDQypUrI2Yz7Xf2fVZeCFzbKwojRowwYWKa/Bvf+IYBxDgA3jfccEMTx0YbbWTixH3bbbc1bgJoMou+7rrrRh988IEJ6+CDD27gbbPNNou/t0G8zXO4T2+QmDVmtYHBENQKuCav7r33XhMOf0lwrdWKE088sSH/Qt6k501flYsLcHbx01flF9Id6lMoAzUtA90ErrF6ByB4+OGHzQ9gi06nXbimTJkS3X777dGxxx5rlqTvu+++CJ3iF154Ifrwww+jH/3oR7H/oUOHGmt/qDSginDFFVd4Wyh0Adc/+clPDL/oHJ922mlGTQKQ8+abb0bbbLON4cfFj53OVu779+8f/fnPfzbAaOTIkbE80sL0Add8v2jRIhPuv/3bvxkVER7mzJnTEMeVV15p/GjwlATXhDNz5kzjh/xM8kXYEGkgLcn306ZNMzPqU6dOXeVd0m9femagwuAElRyoFXDNTDSEKhC0dOnSWNboxUOsPK2++uqxe1+SdUirW4fnApxd/AR5u8k7yCnIKZSBNpWBbgLXWHIDJDMDJ1pzzTUbOm90daEvvvhCXhqu1113nfG/8847R5999pl5hxoK6g3QNddc0xBeUUF0AdfHHXecCVtL8gBrZowhzXi7+CnixfX9L3/5SxP3bbfdVphWX3B95plnmrDHjRtnNiHycOSRRzbEc9RRRxk/l112mXFPA9foskP77bdfw7dK46233mrekxa56free++Zd6iVyC1cv2pQWgXXbEqlLH/++ecR9QiywfXee+9t3NhwvNtuu0UzZswwKiHoZ4cNjV/l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" width="466" /></p><p>Here's what those two-letter satellite codes mean:</p><ul style="text-align: left;"><li><span style="font-family: courier;">GP: <a href="https://en.wikipedia.org/wiki/Global_Positioning_System">GPS</a> 🇺🇸</span></li><li><span style="font-family: courier;">SB: <a href="https://en.wikipedia.org/wiki/GNSS_augmentation#Satellite-based_augmentation_system">SBAS</a> 🏳</span></li><li><span style="font-family: courier;">GA: <a href="https://en.wikipedia.org/wiki/Galileo_(satellite_navigation)">Galileo</a> 🇪🇺</span></li><li><span style="font-family: courier;">BD: <a href="https://en.wikipedia.org/wiki/BeiDou">BeiDou</a> 🇨🇳</span></li><li><span style="font-family: courier;">IM: <a href="https://insidegnss.com/qzsss-indoor-messaging-system/">IMES</a> 🇯🇵(No wikipedia article for this cool technology?)</span></li><li><span style="font-family: courier;">QZ: <a href="https://en.wikipedia.org/wiki/Quasi-Zenith_Satellite_System">QZSS</a> 🇯🇵</span></li><li><span style="font-family: courier;">GL: <a href="https://en.wikipedia.org/wiki/GLONASS">GLONASS</a> 🇷🇺</span></li><li><span style="font-family: courier;">IR: <a href="https://en.wikipedia.org/wiki/Indian_Regional_Navigation_Satellite_System">IRNSS</a> 🇮🇳</span></li></ul><div>The GPS system that everyone knows and loves started (like many pieces of technology) as a military research project. In its early days it was used to track nuclear-capable subs, and was later expanded by the DOD to be a general purpose navigation system[<a href="https://www.nasa.gov/directorates/heo/scan/communications/policy/GPS_History.html">1</a>].</div><div><br /></div><div>Now GPS is used worldwide for virtually all positioning applications. However, the satellites that power GPS are still largely under the control of the US government, and the things that are given can also be taken away.</div><div><br /></div><div>As you can imagine the US hegemony of control is seen as a national security risk by other countries. Given that, some countries have launched their own competing technologies so as not to rely on a rival's generosity. The three largest alternatives to GPS are Russia's GLONASS, China's Beidou, and the EU's Galileo.</div><div><br /></div><div>Here's a summary of these systems:</div><div><br /><b>GPS/GNSS (United States) 🇺🇸</b></div><div>By far the most widely-used navigation system. Originally developed for military use. Accurate down to 10 centimeters or less. This is the system you think of when you hear the word "GPS".</div><div><br /></div><div><b>GLONASS (Russia) 🇷🇺</b></div><div>Competing technology designed in the 1970s by the USSR, now used throughout Russia.</div><div><br /></div><div><b>BeiDou (China) 🇨🇳</b></div><div>Launched in 2000 as a rival to GPS. The positions of the satellites are said to make this system more accurate around Asia. China has 22 operational BeiDou satellites and is expected to continue to launch more and increase the coverage and accuracy of this system. Did you know that China uses datum displacement to intentionally obfuscate GNSS map accuracy? Read more <a href="https://en.wikipedia.org/wiki/Restrictions_on_geographic_data_in_China">here</a>.</div><div><br /></div><div><b>Galileo (EU) 🇪🇺</b></div><div>Launched in 2011 by the European Union. Galileo currently operates 14 satellites and is intended to be more accurate at higher latitudes than GNSS systems such as GPS.</div><div><br /></div><div>There are other systems as we the Indian Regional Navigation Satellite System (IRNSS). These systems are meant to improve the accurate and coverage of specific geographic locations (in this case India).</div>Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com1tag:blogger.com,1999:blog-2870713865752955687.post-11972607327855159972020-07-28T17:33:00.001-07:002020-07-28T17:33:45.636-07:00Install Python 3 on raspberry pi and make it the system defaultAs of this blog post, the raspberry pi still ships with python2.7 as the default. There's also not really an easy way to install python3.8 (again the latest as of this post) as the system default.<div><br /></div><div>I used a global <a href="https://github.com/pyenv/pyenv">pyenv</a> so that the global version can be upgraded and changed easily.</div><div><br /></div><div>The below script will automatically download, compile, and set python3.8.5 as the new system default for your raspberry pi. No prompts necessary.</div><div><br /></div><div>You can run the gist to automatically do this:</div><div><br /></div><b>curl '<a href="https://gist.githubusercontent.com/stephen-mw/341c8194aefb694939b366204156037c/raw/fe2fc6060792dbe3e98bc3fc7830229e0d657bdf/install_python38_on_py.sh">https://gist.githubusercontent.com/stephen-mw/341c8194aefb694939b366204156037c/raw/fe2fc6060792dbe3e98bc3fc7830229e0d657bdf/install_python38_on_py.sh</a>' | sudo bash</b><div><br /></div><div>Or just copy below into your script and execute it:</div><div><br /></div><div><pre style="color: #333333; line-height: 16.25px; margin-bottom: 0px; margin-top: 0px;"><pre style="line-height: 16.25px; margin-bottom: 0px; margin-top: 0px;"><span style="color: #008800; font-style: italic;">#!/usr/bin/env bash</span>
<span style="color: #aa22ff;">set</span> -euo pipefail
<span style="color: #008800; font-style: italic;"># This script downloads, compiles, and installs python3.8 as the system default</span>
<span style="color: #aa22ff;">export </span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #666666;">=</span>3.8.5
apt install -y <span style="color: #bb6622; font-weight: bold;">\</span>
build-essential <span style="color: #bb6622; font-weight: bold;">\</span>
libbz2-dev <span style="color: #bb6622; font-weight: bold;">\</span>
libffi-dev <span style="color: #bb6622; font-weight: bold;">\</span>
liblzma-dev <span style="color: #bb6622; font-weight: bold;">\</span>
libncurses5-dev <span style="color: #bb6622; font-weight: bold;">\</span>
libncursesw5-dev <span style="color: #bb6622; font-weight: bold;">\</span>
libreadline-dev <span style="color: #bb6622; font-weight: bold;">\</span>
libsqlite3-dev <span style="color: #bb6622; font-weight: bold;">\</span>
libssl-dev <span style="color: #bb6622; font-weight: bold;">\</span>
llvm <span style="color: #bb6622; font-weight: bold;">\</span>
python-openssl <span style="color: #bb6622; font-weight: bold;">\</span>
python-pip <span style="color: #bb6622; font-weight: bold;">\</span>
tk-dev <span style="color: #bb6622; font-weight: bold;">\</span>
xz-utils <span style="color: #bb6622; font-weight: bold;">\</span>
zlib1g-dev
<span style="color: #aa22ff;">export </span><span style="color: darkgoldenrod;">OLD_PIP</span><span style="color: #666666;">=</span><span style="color: #aa22ff; font-weight: bold;">$(</span>which pip<span style="color: #aa22ff; font-weight: bold;">)</span>
<span style="color: #aa22ff;">export </span><span style="color: darkgoldenrod;">NEW_PIP</span><span style="color: #666666;">=</span><span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">OLD_PIP</span><span style="color: #aa22ff; font-weight: bold;">}</span>2.7
mv <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">OLD_PIP</span><span style="color: #aa22ff; font-weight: bold;">}</span> <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">NEW_PIP</span><span style="color: #aa22ff; font-weight: bold;">}</span>
ln -s <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">NEW_PIP</span><span style="color: #aa22ff; font-weight: bold;">}</span> <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">OLD_PIP</span><span style="color: #aa22ff; font-weight: bold;">}</span>
<span style="color: #aa22ff;">export </span><span style="color: darkgoldenrod;">PYENV_ROOT</span><span style="color: #666666;">=</span>/etc/pyenv
<span style="color: #aa22ff;">export </span><span style="color: darkgoldenrod;">PATH</span><span style="color: #666666;">=</span><span style="color: #bb4444;">"$PYENV_ROOT/bin:$PATH"</span>
<span style="color: #aa22ff; font-weight: bold;">if</span> <span style="color: #666666;">[[</span> -d <span style="color: #bb4444;">"${PYENV_ROOT}"</span> <span style="color: #666666;">]]</span>; <span style="color: #aa22ff; font-weight: bold;">then</span>
<span style="color: #aa22ff; font-weight: bold;"> </span>rm -rfv -- <span style="color: #bb4444;">"${PYENV_ROOT}"</span>
<span style="color: #aa22ff; font-weight: bold;">fi</span>
git clone https://github.com/pyenv/pyenv.git <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">PYENV_ROOT</span><span style="color: #aa22ff; font-weight: bold;">}</span>
<span style="color: #008800; font-style: italic;"># Can't fit in /tmp because it's a ramfs</span>
<span style="color: #aa22ff;">local </span><span style="color: darkgoldenrod;">TMPDIR</span><span style="color: #666666;">=</span><span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">PYENV_ROOT</span><span style="color: #aa22ff; font-weight: bold;">}</span>/tmp
mkdir <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">TMPDIR</span><span style="color: #aa22ff; font-weight: bold;">}</span>
<span style="color: #008800; font-style: italic;"># The latest version as of now</span>
<span style="color: #aa22ff;">echo</span> <span style="color: #bb4444;">"Setting system python to ${VERSION}. This may take several minutes..."</span>
<span style="color: darkgoldenrod;">CFLAGS</span><span style="color: #666666;">=</span><span style="color: #bb4444;">"-O2"</span> <span style="color: darkgoldenrod;">TMPDIR</span><span style="color: #666666;">=</span><span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">TMPDIR</span><span style="color: #aa22ff; font-weight: bold;">}</span> pyenv install <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #aa22ff; font-weight: bold;">}</span>
rm -rf -- <span style="color: #bb4444;">"${TMPDIR}"</span>
<span style="color: #008800; font-style: italic;"># Set the global version</span>
pyenv global <span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #aa22ff; font-weight: bold;">}</span>
<span style="color: #008800; font-style: italic;"># Latest</span>
update-alternatives --install <span style="color: #aa22ff; font-weight: bold;">$(</span>which python<span style="color: #aa22ff; font-weight: bold;">)</span> python /etc/pyenv/versions/<span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #aa22ff; font-weight: bold;">}</span>/bin/python 1
update-alternatives --install <span style="color: #aa22ff; font-weight: bold;">$(</span>which pip<span style="color: #aa22ff; font-weight: bold;">)</span> pip /etc/pyenv/versions/<span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #aa22ff; font-weight: bold;">}</span>/bin/pip 1
<span style="color: #008800; font-style: italic;"># 2.7</span>
update-alternatives --install <span style="color: #aa22ff; font-weight: bold;">$(</span>which python<span style="color: #aa22ff; font-weight: bold;">)</span> python /usr/bin/python2.7 2
update-alternatives --install <span style="color: #aa22ff; font-weight: bold;">$(</span>which pip<span style="color: #aa22ff; font-weight: bold;">)</span> pip /usr/bin/pip2.7 2
<span style="color: #008800; font-style: italic;"># Lastly, set the system python to our new version</span>
update-alternatives --set python /etc/pyenv/versions/<span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #aa22ff; font-weight: bold;">}</span>/bin/python
update-alternatives --set pip /etc/pyenv/versions/<span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #aa22ff; font-weight: bold;">}</span>/bin/pip
pip install -U pip
cat <<<span style="color: #bb4444;">"HELP"</span>
Python<span style="color: #aa22ff; font-weight: bold;">${</span><span style="color: darkgoldenrod;">VERSION</span><span style="color: #aa22ff; font-weight: bold;">}</span> is now your system default.
If you want to roll your system back to 2.7, simply run:
sudo update-alternatives --set python /usr/bin/python2.7
sudo update-alternatives --set pip /usr/bin/pip2.7
HELP</pre></pre></div>Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-75264613941894106182018-08-17T14:26:00.003-07:002018-08-17T16:48:35.849-07:00Shinobi on the Raspberry Pi 3 B+<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="background-color: white; border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; line-height: 1.25; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em; text-align: left;">
<br /></div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
The Raspberry Pi is a $35 single board computer that runs on a 64-bit ARM processor. It uses the Broadcom BCM2835 SoC which includes hardware-accelerated h264 encoding/decoding, making it a great choice for running a small Shinobi setup with network h264 cameras.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
In fact, there's even a wireless $10 version called the <a href="https://www.raspberrypi.org/products/raspberry-pi-zero-w/" style="background-color: transparent;">Raspberry Pi Zero W</a>!</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
<a href="https://shinobi.video/">Shinobi</a> is a powerful CCTV software that forms the "brain" for your cameras, allowing you to configure how, what, and when they record. </div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
If you've ever futzed around with the CCTV software that comes preinstalled with NVR cameras you'll realize quickly how awful they are. I fully replaced my CCTV NVR with a PoE switch attached to a Raspberry Pi.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Together with the Raspberry Pi 3, you have an affordable, reliable, and power-efficient way to manage your CCTV setup. This "guide" will walk you through my setup and provide some tips if you want to use the RPI for this purpose.</div>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
The setup</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
My setup includes 4 cameras: 2x 1080p@30, and 2x 720p@30. I have them monitoring for motion and recording. The RPI is able to handle this workload with surprisingly little power usage.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
In order for this setup to work, there's a few conditions that must be met:</div>
<ol style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;">
<li style="box-sizing: border-box;">No transcoding. It's simply too CPU intensive even with hardware-accelerated h264_omx encoder. For any recording/streaming you'll need to set the video codec to "copy" (or possibly the jpeg API).</li>
<li style="box-sizing: border-box; margin-top: 0.25em;">Depending on the camera quality settings, you'll need to bump the GPU memory share up to 256MB. Even to me this seemed too high, but without it I was getting mmal decoding errors with more than 2 1080p@30 NVR camera.</li>
<li style="box-sizing: border-box; margin-top: 0.25em;">For any decoding you'll need to use the hardware-accelerated h264_mmal codec. Without specifying this codec there will be too much CPU usage. Using MMAL ensures that the heavy lifting of deciding the h264 stream is done on the GPU.</li>
<li style="box-sizing: border-box; margin-top: 0.25em;">Real 2.5a power supply. Your RPI needs all of it.</li>
<li style="box-sizing: border-box; margin-top: 0.25em;">(Optional) Active cooling. My RPI case has a small fan hooked up the 3v power supply. I have small heatsinks attached to the SoC.</li>
</ol>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Configuration</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
The default <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">ffmpeg</code> binary installed from apt includes all of the necessary codecs to use RPI's GPU for hardware acceleration. There's no need to do any compiling or ffmpeg, just get it from apt and you're done.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Despite what you find online. There is no need to recompile FFMPEG on the Raspberry Pi to do hardware accelerated h264 encoding/decoding! It's amazing how out-of-date a lot of these guides are.</div>
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; overflow: visible; padding: 0px; word-break: normal; word-wrap: normal;"># ffmpeg
ffmpeg version 3.2.10-1~deb9u1+rpt2 Copyright (c) 2000-2018 the FFmpeg
# The encoder to use (if any -- see comment about "copy")
$ ffmpeg -encoders | grep omx
V..... h264_omx OpenMAX IL H.264 video encoder (codec h264)
# The decoder to use
$ ffmpeg -decoders | grep mmal
V..... h264_mmal h264 (mmal) (codec h264)
V..... mpeg2_mmal mpeg2 (mmal) (codec mpeg2video)
V..... mpeg4_mmal mpeg4 (mmal) (codec mpeg4)
V..... vc1_mmal vc1 (mmal) (codec vc1)
</code></pre>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Configuring Shinobi</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
I made a few <a href="https://gitlab.com/Shinobi-Systems/Shinobi/merge_requests/19">small tweaks</a> to Shinobi to expose the Raspberry Pi's native decoding methods. The changes are in the dev branch now but should be merged into master soon. </div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
You can check out the repo here: https://gitlab.com/Shinobi-Systems/Shinobi. Depending on when you read this blog you may be able to checkout master.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
There are several guides on the site for getting the software installed.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
To expose the hardware acceleration method select <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">yes</code> for hardware acceleration dropdown. Leave the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">HWAccel</code> option as <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">auto</code> and select <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">H.264 (Raspberry Pi)</code> as the decoder.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
<a href="https://camo.githubusercontent.com/dc769191a02bf66f575712a3c313566db67100c0/68747470733a2f2f692e696d6775722e636f6d2f56356e61777a332e706e67" style="background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;" target="_blank"><img alt="" data-canonical-src="https://i.imgur.com/V5nawz3.png" src="https://camo.githubusercontent.com/dc769191a02bf66f575712a3c313566db67100c0/68747470733a2f2f692e696d6775722e636f6d2f56356e61777a332e706e67" style="border-style: none; box-sizing: content-box; max-width: 100%;" /></a></div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
This will use the hardware-accelerated h264_mmal codec.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
For streaming/output I highly recommend you set it to <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">copy</code> to save yourself the CPU cycles of transcoding. If you need to encode in h264, make sure to use the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">h264_omx</code> codec so that it's hardware accelerated.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Another option for transcoding is simply to setup a cron to do the transcoding in the background with low CPU affinity.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
That's about it as far as configurations go.</div>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Storage</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
You basically have three options: root storage, attached storaged, and network-attached storage.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
The raspberry pi's main storage is micro SD. You can use the root storage as your primary storage if you're careful about space and set the appropriate video expirations.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
You can attach storage via the USB interface. Be careful with additional power draw if your device is unpowered.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
The last option is to use a network-attached storage device. This can be a NAS or something similar. This method is the most flexible if the hardware is available to you, such as a NAS server.</div>
<h1 style="background-color: white; border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; line-height: 1.25; margin: 24px 0px 16px; padding-bottom: 0.3em;">
Troubleshooting</h1>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
mmal encoding errors</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
The most common problem I encountered was mmal encoding errors. If your cameras are restarting because of these errors, bump up the available memory to the GPU. You may also need to downscale the quality/bitrate of your cameras.</div>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Unstable Pi / reboots</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Make sure you're using a 2.5a (or above) power supply. Most power supplies do not supply 2.5a. Usually ones that are marketed for iPads or tablets will supply the amperage, but you must check the back of your adapter to see what its rating is.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Depending on your setup (and how hard you're pushing your Pi), you may need active cooling. You can also try adding a heatsink to the CPU/GPU SoC.</div>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Slow / sluggish performance</h3>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
If you're using the h264_mmal codec with a 1080p@30fps camera, it takes about 100% of a single CPU. If you're seeing higher CPU usage (such as 200-250%) you're probably not using the codec or something is else is misconfigured.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
You can check by running <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">ps aux | grep ffmpeg</code> and taking note of the setting just before the <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">-i rtsp://...</code> line. It should say <code style="background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0.4em;">-c:v h264_mmal</code>.</div>
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; line-height: 1.45; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; overflow: visible; padding: 0px; word-break: normal; word-wrap: normal;">$ sudo ps aux | grep ffmpeg
ffmpeg ... -c:v h264_mmal -i rtsp://....</code></pre>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com27tag:blogger.com,1999:blog-2870713865752955687.post-22205604237987682002018-06-11T17:29:00.002-07:002018-06-11T17:29:48.889-07:00Working with nulls with sql databases in Golang<div dir="ltr" style="text-align: left;" trbidi="on">
<div>
Go is typed with no generics, so it's a little tricky working with databases where null values abound.<br />
<br />
the sql package includes structs such as sql.NullString, but it's confusing for users to get a json response that looks like this, which is how the value is represented internally:<br />
<br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">{
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>foo<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: {
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Valid<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">true</span>,
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Value<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">5</span>
}
}</pre>
<br />
Below is a working golang HTTP server that handles null strings. It reads and writes to a sqlite3 database (in memory). When rows contain null values, they'll be properly displayed as null.<br />
<br />
The trick to making things work is the <a href="https://gopkg.in/guregu/null.v3">null.v3</a> library, which implements the <a href="https://godoc.org/gopkg.in/guregu/null.v3#String.MarshalJSON">json marshal and unmarshal </a>methods necessary to return a null value when querying the database.<br />
<br />
<a href="https://gist.github.com/stephen-mw/f55cb15f1d097f0fc3a81221a5835804">Gist here.</a><br />
<br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-k" style="box-sizing: border-box; color: #d73a49;">package</span> main
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">import</span> (
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>database/sql<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>encoding/json<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>log<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>net/http<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>strconv<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
_ <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/mattn/go-sqlite3<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>gopkg.in/guregu/null.v3<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
)
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> DB is the database connector</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">var</span> <span class="pl-smi" style="box-sizing: border-box;">DB</span> *sql.<span class="pl-smi" style="box-sizing: border-box;">DB</span>
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> Person represents a single row in a database. Using the type null.</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">type</span> <span class="pl-v" style="box-sizing: border-box; color: #e36209;">Person</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">struct</span> {
<span class="pl-v" style="box-sizing: border-box; color: #e36209;">Name</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">string</span> <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">`</span>json:"id"<span class="pl-pds" style="box-sizing: border-box;">`</span></span>
<span class="pl-v" style="box-sizing: border-box; color: #e36209;">Age</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">int</span> <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">`</span>json:"age"<span class="pl-pds" style="box-sizing: border-box;">`</span></span>
<span class="pl-v" style="box-sizing: border-box; color: #e36209;">NickName</span> null.<span class="pl-smi" style="box-sizing: border-box;">String</span> <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">`</span>json:"nickname"<span class="pl-pds" style="box-sizing: border-box;">`</span></span> <span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> Optional</span>
}
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> InsertPerson adds a person to the database</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">InsertPerson</span>(<span class="pl-v" style="box-sizing: border-box; color: #e36209;">p</span> <span class="pl-v" style="box-sizing: border-box; color: #e36209;">Person</span>) {
<span class="pl-smi" style="box-sizing: border-box;">cnx</span>, <span class="pl-smi" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> DB.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Prepare</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;">`</span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"> INSERT INTO people (name, age, nickname) VALUES (?, ?, ?)<span class="pl-pds" style="box-sizing: border-box;">`</span></span>)
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">defer</span> cnx.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Close</span>()
log.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Printf</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Adding person: <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">%v</span><span class="pl-cce" style="box-sizing: border-box;">\n</span><span class="pl-pds" style="box-sizing: border-box;">"</span></span>, p)
cnx.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Exec</span>(p.<span class="pl-smi" style="box-sizing: border-box;">Name</span>, p.<span class="pl-smi" style="box-sizing: border-box;">Age</span>, p.<span class="pl-smi" style="box-sizing: border-box;">NickName</span>)
}
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> GetPeople will retur N number of people from database</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">GetPeople</span>(<span class="pl-v" style="box-sizing: border-box; color: #e36209;">n</span> <span class="pl-v" style="box-sizing: border-box; color: #e36209;">int</span>) []<span class="pl-v" style="box-sizing: border-box; color: #e36209;">Person</span> {
<span class="pl-smi" style="box-sizing: border-box;">people</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">make</span>([]Person, <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">0</span>)
<span class="pl-smi" style="box-sizing: border-box;">rows</span>, <span class="pl-smi" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> DB.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Query</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">`</span>SELECT name, age, nickname from people LIMIT ?<span class="pl-pds" style="box-sizing: border-box;">`</span></span>, n)
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">for</span> rows.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Next</span>() {
<span class="pl-smi" style="box-sizing: border-box;">p</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">new</span>(Person)
rows.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Scan</span>(&p.<span class="pl-smi" style="box-sizing: border-box;">Name</span>, &p.<span class="pl-smi" style="box-sizing: border-box;">Age</span>, &p.<span class="pl-smi" style="box-sizing: border-box;">NickName</span>)
people = <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">append</span>(people, *p)
}
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">return</span> people
}
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">addPersonRouter</span>(<span class="pl-v" style="box-sizing: border-box; color: #e36209;">w</span> <span class="pl-v" style="box-sizing: border-box; color: #e36209;">http</span>.<span class="pl-v" style="box-sizing: border-box; color: #e36209;">ResponseWriter</span>, <span class="pl-v" style="box-sizing: border-box; color: #e36209;">r</span> *<span class="pl-v" style="box-sizing: border-box; color: #e36209;">http</span>.<span class="pl-v" style="box-sizing: border-box; color: #e36209;">Request</span>) {
r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">ParseForm</span>()
<span class="pl-smi" style="box-sizing: border-box;">age</span>, <span class="pl-smi" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> strconv.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Atoi</span>(r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">FormValue</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>age<span class="pl-pds" style="box-sizing: border-box;">"</span></span>))
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> Get nickname from the form and create a new null.String. If the string</span>
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> is empty, it will be considered invalid (null) in the database and not</span>
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> empty</span>
<span class="pl-smi" style="box-sizing: border-box;">nick</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">FormValue</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>nickname<span class="pl-pds" style="box-sizing: border-box;">"</span></span>)
<span class="pl-smi" style="box-sizing: border-box;">nickName</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> null.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">NewString</span>(
nick, nick != <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span><span class="pl-pds" style="box-sizing: border-box;">"</span></span>)
<span class="pl-smi" style="box-sizing: border-box;">p</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> Person{
Name: r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">FormValue</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>name<span class="pl-pds" style="box-sizing: border-box;">"</span></span>),
Age: age,
NickName: nickName,
}
<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">InsertPerson</span>(p)
w.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">WriteHeader</span>(http.<span class="pl-smi" style="box-sizing: border-box;">StatusCreated</span>)
}
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">getPeopleRouter</span>(<span class="pl-v" style="box-sizing: border-box; color: #e36209;">w</span> <span class="pl-v" style="box-sizing: border-box; color: #e36209;">http</span>.<span class="pl-v" style="box-sizing: border-box; color: #e36209;">ResponseWriter</span>, <span class="pl-v" style="box-sizing: border-box; color: #e36209;">r</span> *<span class="pl-v" style="box-sizing: border-box; color: #e36209;">http</span>.<span class="pl-v" style="box-sizing: border-box; color: #e36209;">Request</span>) {
r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">ParseForm</span>()
<span class="pl-smi" style="box-sizing: border-box;">limit</span>, <span class="pl-smi" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> strconv.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Atoi</span>(r.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">FormValue</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>limit<span class="pl-pds" style="box-sizing: border-box;">"</span></span>))
<span class="pl-smi" style="box-sizing: border-box;">people</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">GetPeople</span>(limit)
<span class="pl-smi" style="box-sizing: border-box;">peopleJSON</span>, <span class="pl-smi" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> json.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Marshal</span>(people)
w.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Header</span>().<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Set</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Content-Type<span class="pl-pds" style="box-sizing: border-box;">"</span></span>, <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>application/json<span class="pl-pds" style="box-sizing: border-box;">"</span></span>)
w.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Write</span>(peopleJSON)
}
<span class="pl-c" style="box-sizing: border-box; color: #6a737d;"><span class="pl-c" style="box-sizing: border-box;">//</span> CreateTable is a helper function to create the table for the first run</span>
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">CreateTable</span>() <span class="pl-v" style="box-sizing: border-box; color: #e36209;">error</span> {
<span class="pl-smi" style="box-sizing: border-box;">createSQL</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> <span class="pl-s" style="box-sizing: border-box; color: #032f62;">`</span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"> CREATE TABLE people (</span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"> id INTEGER PRIMARY KEY AUTOINCREMENT,</span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"> name TXT NOT NULL,</span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"> age INTEGER NOT NULL,</span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"> nickname TXT</span>
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"> );<span class="pl-pds" style="box-sizing: border-box; color: #032f62;">`</span></span>
<span class="pl-smi" style="box-sizing: border-box;">statement</span>, <span class="pl-smi" style="box-sizing: border-box;">err</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">:=</span> DB.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Prepare</span>(createSQL)
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">if</span> err != <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">nil</span> {
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">return</span> err
}
statement.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Exec</span>()
statement.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Close</span>()
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">return</span> <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">nil</span>
}
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #6f42c1;">main</span>() {
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">var</span> <span class="pl-smi" style="box-sizing: border-box;">err</span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">error</span>
DB, err = sql.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Open</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>sqlite3<span class="pl-pds" style="box-sizing: border-box;">"</span></span>, <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>:memory:<span class="pl-pds" style="box-sizing: border-box;">"</span></span>)
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">if</span> err != <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">nil</span> {
log.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Fatal</span>(err)
}
err = <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">CreateTable</span>()
<span class="pl-k" style="box-sizing: border-box; color: #d73a49;">if</span> err != <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">nil</span> {
log.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">Fatal</span>(err)
}
http.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">HandleFunc</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>/add<span class="pl-pds" style="box-sizing: border-box;">"</span></span>, addPersonRouter)
http.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">HandleFunc</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>/list<span class="pl-pds" style="box-sizing: border-box;">"</span></span>, getPeopleRouter)
http.<span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">ListenAndServe</span>(<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>:8080<span class="pl-pds" style="box-sizing: border-box;">"</span></span>, <span class="pl-c1" style="box-sizing: border-box; color: #005cc5;">nil</span>)
}</pre>
</div>
<div>
<br /></div>
<div>
Here's some examples of the server when it's running<br />
<br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ curl -XPOST <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>localhost:8080/add?name=Joseph&age=25&nickname=Joe<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
$ curl -XPOST <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>localhost:8080/add?name=Stephen&age=33<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
$ curl -s <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">'</span>localhost:8080/list?limit=2<span class="pl-pds" style="box-sizing: border-box;">'</span></span> <span class="pl-k" style="box-sizing: border-box; color: #d73a49;">|</span> jq
[
{
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>id<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Joseph<span class="pl-pds" style="box-sizing: border-box;">"</span></span>,
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>age<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: 25,
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>nickname<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Joe<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
},
{
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>id<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: <span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Stephen<span class="pl-pds" style="box-sizing: border-box;">"</span></span>,
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>age<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: 33,
<span class="pl-s" style="box-sizing: border-box; color: #032f62;"><span class="pl-pds" style="box-sizing: border-box;">"</span>nickname<span class="pl-pds" style="box-sizing: border-box;">"</span></span>: null
}
]</pre>
<div>
<br /></div>
</div>
<div>
There you go. Now you can read and write valid or invalid values to your database.</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-22410310776581682722015-12-18T15:33:00.002-08:002015-12-18T15:33:53.031-08:00Git cheat sheet<div dir="ltr" style="text-align: left;" trbidi="on">
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em;">
Creating a feature branch</h1>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Creating a feature branch is a good way to keep your testing out of the main branch. You can hack away at your code without disturbing the general workflow.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
The following command will create a feature branch that tracks master. Pushing it with the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0px;">-u origin</code> flag will autmatically make your local version of the branch track the remote version:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"> $ git checkout master && git pull
$ git checkout -t -b "some-feature-branch-name"
$ git push -u origin "some-feature-branch-name"
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Also, since this is a feature branch you're free to do force commits and cleanup your git history.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
You can see what your branches are tracking and what their origin is with the following command:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">git branch -vv
1432-rb-force-safety-switch 62d5af7 [origin/1432-rb-force-safety-switch] Refuse rb if path contains keys.
* develop 5f56434 [origin/develop: ahead 233, behind 2] Merge branch 'release-1.8.12'
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
And to see where "origin" points to:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">$ git remote -v
origin git@github.com:stephen-mw/aws-cli.git (fetch)
origin git@github.com:stephen-mw/aws-cli.git (push)
upstream git@github.com:aws/aws-cli.git (fetch)
upstream git@github.com:aws/aws-cli.git (push)
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
In the above example, I can push to either "upstream" (which in this case is the official aws repo), or "origin", which is my forked repo.</div>
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin: 1em 0px 16px; padding-bottom: 0.3em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#creating-a-git-tag" id="user-content-creating-a-git-tag" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Creating a Git Tag</h1>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
A tag is a point-in-time reference to a git branch. Tags are immutable snapshots of the repo that can't be altered once they are created (though they can be deleted and recreated). They are useful for tasks such as deployments or ensuring your work won't be altered by others.</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"> # This will create a tag called "mysql-1380235429"
$ git tag -a -m "Deploying mysql update" mysql-`date +%s`
$ git push --tags
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Now the tag can be checked out in the usual method.</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"> $ git checkout mysql-1380235429
</code></pre>
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin: 1em 0px 16px; padding-bottom: 0.3em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#preparing-your-branch-for-a-pull-request" id="user-content-preparing-your-branch-for-a-pull-request" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Preparing Your Branch for a Pull Request</h1>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
A pull request should be done before anything is merged into the master branch.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Before asking someone to review your work, you should take a few minutes and make sure it's really finished. You'd be surprised what things can slip through.</div>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#diff-against-master" id="user-content-diff-against-master" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1.2; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Diff Against Master</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
The first thing you want to do is diff your branch against the master branch. This allows you to catch simple bugs before pushing anything upstream.</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">git diff master
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
This will tell you exactly what's different between your branch and the master branch. It will also highlight things such as trailing whitespace.</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#rebasing-your-branch-against-master-or-a-different-branch" id="user-content-rebasing-your-branch-against-master-or-a-different-branch" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Rebasing your branch against master (or a different branch)</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
You can think of rebasing as doing the following actions: 1. Take all recent changes and stash them away 2. Pull down the most recent changes from a different branch 3. Attempt to apply your stashed changes on top of the new changes one at a time.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Here's how to rebase your branch against master:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">git checkout master
git pull
git checkout my_feature_branch
git rebase master
git push origin +my_feature_branch
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Many times there's conflicts in this process if there were multiple changes to the same file. The way to fix a conflict is to change it during the rebase and add it again:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">(fix the conflicts within the file)
git add some_conflicted_file
git rebase --continue
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
If you think there's a problem then you can abort the rebase with <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0px;">--abort</code>.</div>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#squashing-commits" id="user-content-squashing-commits" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1.2; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Squashing Commits</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
It's important that you branch is tidy because it makes rolling back bad changes a lot easier. You can squash all of your commits into one or two commits using the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0px;">rebase</code> command.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
First, run <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0px;">git log</code> and find the commit that you want to squash into. Usually this is the first commit on your feature branch.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Next, interactively rebase against that commit:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">git rebase --interactive shdf8032hfohsdofhsdohf80h^
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
This will rebase every commit <em style="box-sizing: border-box;">after</em> the sha.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Follow the instructions for rebasing. Usually you just want to change the "pick" to a "squash" or "s". In the below example, all commits will be squashed into the top commit (which is the oldest):</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">pick e775ebe Refactor regex to avoid duplication
s 3bb23fd Add support for spaces within unquoted values
s e36d71a Support '-' char in a key name
s 16eda81 Remove unused import in test module
s 403c7ec Add bugfixes to changelog
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
You will have a chance to rewrite the commit message to better include all of the changes.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
After you're finished, do a diff against master again just to make sure things don't go wrong. Then force push your branch to origin.</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"># Make sure it still looks good
git diff master
git push origin +my_feature_branch
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#send-out-the-pr" id="user-content-send-out-the-pr" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1.2; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Send Out the PR</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Go to github.com and find your branch. Compare it with master and send out the PR. You should ask someone specifically to review your changes and include the following information:</div>
<ul style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px; margin-top: 0px; padding: 0px 0px 0px 2em;">
<li style="box-sizing: border-box;">Why did you change this?</li>
<li style="box-sizing: border-box;">What have you changed?</li>
<li style="box-sizing: border-box;">How have you tested these changes?</li>
<li style="box-sizing: border-box;">What are the risks involved with these changes?</li>
</ul>
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin: 1em 0px 16px; padding-bottom: 0.3em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#oh-no-i-rebase-my-branch-and-lost-a-lot-of-history-im-doomed" id="user-content-oh-no-i-rebase-my-branch-and-lost-a-lot-of-history-im-doomed" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Oh no! I rebase my branch and lost a lot of history! I'm doomed!</h1>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Fear not. With git nothing is ever truly lost. If you made some mistake and you're currently in the rebase process then you can abort it with <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0px;">git rebase --abort</code>. If you've already commited, pushed, etc, then you can use the fantastic <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0px;">git reflog</code> tool to go back to a different commit.</div>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em;">
<a aria-hidden="true" class="anchor" href="https://gist.github.com/stephen-mw/42934a9a3af1b517c144#using-git-reflog" id="user-content-using-git-reflog" style="box-sizing: border-box; color: #4078c0; display: inline-block; line-height: 1.2; margin-left: -18px; padding-right: 2px; text-decoration: none;"><span class="octicon octicon-link" style="-webkit-font-smoothing: antialiased; -webkit-user-select: none; box-sizing: border-box; color: black; display: inline-block; font-family: octicons; font-size: 16px; font-stretch: normal; font-weight: normal; line-height: 1; text-rendering: auto; vertical-align: middle; visibility: hidden;"></span></a>Using git reflog</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
In the following example, I'm going to force my branch back to the moment before I rebased and broke everything:</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
First, find the commit that came right before your rebase:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">git reflog
5f56434 HEAD@{0}: pull upstream master: Fast-forward
ed610bc HEAD@{1}: checkout: moving from 1432-rb-force-safety-switch to develop
62d5af7 HEAD@{2}: rebase -i (finish): returning to refs/heads/1432-rb-force-safety-switch
62d5af7 HEAD@{3}: rebase -i (squash): Refuse rb if path contains keys.
781b4da HEAD@{4}: rebase -i (start): checkout 781b4da0dcc65736297464dd73da442daad4cf2c^
4350e25 HEAD@{5}: commit: Use two vars for readability. <---- ding ding ding
781b4da HEAD@{6}: checkout: moving from ed610bc9d38244feeaf0b640781da8ab01808f4e to 1432-rb-force-safety-switch
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25.6px; margin-bottom: 16px;">
Next, we'll checkout that sha and then force push it</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; font-stretch: normal; line-height: 1.45; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">git checkout 4350e25
git log # make sure it's what you want
git push +some_branch</code></pre>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-85549094099022318422015-12-12T11:53:00.000-08:002015-12-13T13:20:54.295-08:00Using ssh-import-id to manage authorized keys<div dir="ltr" style="text-align: left;" trbidi="on">
<h1 style="background-color: white; border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em;">
ssh-import-id</h1>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
While poking around in my <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">~/.ssh</code> directory (in order to inspect and harden some of my SSH configurations -- more on that later), I noticed a file that I have never seen before:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">ssh_import_id
</code></pre>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
I was surprised to this this file, especially in a directory related to openssh. Opening the file I saw this:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">{
"_comment_": "This file is JSON syntax and will be loaded by ssh-import-id to obtain the URL string, which defaults to launchpad.net. The following URL *must* be an https address with a valid, signed certificate!!! %s is the variable that will be filled by the ssh-import-id utility.",
"URL": "https://launchpad.net/~%s/+sshkeys"
}
</code></pre>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
<code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">ssh-import-id</code> is a utility included with Ubuntu 14.04+ that, according to the man page "will securely contact a public key server and retrieve one or more user's public keys". In other words it's a way to manage your authorized_keys file via an external API.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
You have two options: launchpad.net's user directory or github. Running the utility will fetch and update the authorized_keys file based on the remote API.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
For example, the following command will pull down my authorized_keys on github and update the file<code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">/home/stephen/.ssh/authorized_keys</code> (since that's the user running the command)</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">stephen@cato:/etc/ssh$ ssh-import-id gh:stephen-mw
2015-11-30 21:44:04,813 INFO Already authorized ['4096', 'SHA256:3bLv3IXbSzhQpCnchqQprIRHXWPoI+PPW4xwguR6ktE', 'stephen-mw@github/10248951', '(RSA)']
2015-11-30 21:44:04,817 INFO Already authorized ['4096', 'SHA256:5ZtG8hD7l9+yU7I1S17FunmrPR5u6tEcRi0xa6wQGD4', 'stephen-mw@github/12837805', '(RSA)']
2015-11-30 21:44:04,817 INFO [2] SSH keys [Authorized]
</code></pre>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
The way it works is pretty simple. Github exposes an API for authorized keys. The utility simply makes a request to this endpoint and loads the output into the file. The utility is smart enough to know when keys change (that is, if you added all of your keys with ssh-import-id) and will keep things up-to-date.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
By the way, did you know that github has an API for retrieving any public key? If that weirds you out, remember that they're called public keys for a reason! <a href="https://api.github.com/users/torvalds/keys" style="background-color: transparent; box-sizing: border-box; color: #4078c0; text-decoration: none;">Here's Linus Torvalds public key</a>. It's a 2048 RSA key.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
You can add something like this to your crontab to update your key once a day at 4 am, and then once again if ever there's a restart. The second option is to ensure that servers/hosts that have been turned off for a long time can be accessed immediately.</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"># Pull down my github keys and add them to my user
0 4 * * * ssh-import-id gh:stephen-mw
@reboot ssh-import-id gh:stephen-mw
</code></pre>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
I find this to be especially useful on small embedded computers, such as a raspberry pi. When the raspberry pi is started after a long period it will automatically pick up my newest keys.</div>
<h2 style="background-color: white; border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">
Security</h2>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
My first problem was a file appearing magically in my ~/.ssh/ directory. I consider this directory a <i>sacred</i> place and don't like uninvited files here. Apart from that, the application bills itself as "secure" so I took a look at the source. Mostly it looks fine, but there are some things I would like to see different:</div>
<ul style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px; margin-top: 0px; padding: 0px 0px 0px 2em;">
<li style="box-sizing: border-box;">Github usernames can change and that string is the only thing used to pull down the key. If you change your name you'll need to hunt down any instance of this program and update it. That's annoying with embedded systems, which is exactly the problem I'm hoping to solve with this application.</li>
<li style="box-sizing: border-box;">For SSL, the application uses Python's <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">urlib</code> and attempts to fallback on shelling to <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">wget</code>. However, there's no guarantee that wget will honor https requests <em style="box-sizing: border-box;">only</em>. In fact this can be disabled via ~/.wgetrc. They're relying on <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">wget's</code> default behavior without being explicit.</li>
<li style="box-sizing: border-box;">It checks only if the SSL cert is valid, but doesn't try very hard to see how valid it is. I would have preferred to see it reject any TLS versions lower than 1.2 and only accept EV certificates, since both domains use EV and TLS 1.2.</li>
</ul>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
The last issue worries me the most. <a href="http://arstechnica.com/security/2015/03/two-weeks-on-superfish-debacle-still-causing-pain-for-some-lenovo-customers/" style="background-color: transparent; box-sizing: border-box; color: #4078c0; text-decoration: none;">Superfish</a>, <a href="https://blog.mozilla.org/security/2015/04/02/distrusting-new-cnnic-certificates/" style="background-color: transparent; box-sizing: border-box; color: #4078c0; text-decoration: none;">CNNIC</a>, and <a href="http://arstechnica.com/security/2015/11/dell-does-superfish-ships-pcs-with-self-signed-root-certificates/" style="background-color: transparent; box-sizing: border-box; color: #4078c0; text-decoration: none;">eDellRoot</a> all show that rogue certificate authorities are a real and not theoretical problem.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px;">
But like most things in the world, it's a trade-off. If you find the convenience outweighs the security risk -- and I do -- then give <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">ssh-import-id</code> a try.</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-23071646166186080742015-11-18T17:38:00.000-08:002015-11-18T17:38:04.081-08:00List all keys in an S3 bucket using golang<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px;">
Here's a golang snippet that will list all of the keys under your S3 bucket using the official aws-sdk-go:</div>
<div class="highlight highlight-source-go" style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 14px; line-height: 22.4px; margin-bottom: 16px; overflow: visible !important;">
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">package</span> main
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">import</span> (
<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>fmt<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/aws/aws-sdk-go/aws<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/aws/aws-sdk-go/aws/session<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/aws/aws-sdk-go/service/s3<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
)
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #795da3;">main</span>() {
<span class="pl-smi" style="box-sizing: border-box;">svc</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> s3.<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">New</span>(session.<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">New</span>(), &aws.<span class="pl-smi" style="box-sizing: border-box;">Config</span>{Region: aws.<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">String</span>(<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>us-east-1<span class="pl-pds" style="box-sizing: border-box;">"</span></span>)})
<span class="pl-smi" style="box-sizing: border-box;">params</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> &s3.<span class="pl-smi" style="box-sizing: border-box;">ListObjectsInput</span>{
Bucket: aws.<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">String</span>(<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>bucket<span class="pl-pds" style="box-sizing: border-box;">"</span></span>),
}
<span class="pl-smi" style="box-sizing: border-box;">resp</span>, <span class="pl-smi" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> svc.<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">ListObjects</span>(params)
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">for</span> <span class="pl-smi" style="box-sizing: border-box;">_</span>, <span class="pl-smi" style="box-sizing: border-box;">key</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">range</span> resp.<span class="pl-smi" style="box-sizing: border-box;">Contents</span> {
fmt.<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">Println</span>(*key.<span class="pl-smi" style="box-sizing: border-box;">Key</span>)
}
}</pre>
</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com3tag:blogger.com,1999:blog-2870713865752955687.post-10530301360773170412015-11-15T13:18:00.000-08:002015-12-06T10:09:15.564-08:00What's the difference between a PRNG and a CSPRNG?<div dir="ltr" style="text-align: left;" trbidi="on">
<h1 style="background-color: white; border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em;">
PRNG vs CSPRNG</h1>
<h1 style="background-color: white; border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em;">
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
What's the different between a pseudo-random number generator and a <em style="box-sizing: border-box;">cryptographically-secure</em> pseudo-random number generator? A recommendation from the NIST.</div>
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
The NIST ran various tests (defined in a publication known as <a href="http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf">SP800-22</a>) to determine which PRNG algorithms produced the best output given a certain criteria.</div>
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
The result and recommendation for these tests can be read in another publication called <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">SP800-90</a>. Skip down to Appendix C <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">(Informative) DRBG Mechanism Selection</code> to see the good stuff.</div>
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
Three algorithms are determined to be cryptographically-secure pseudo-random number generators:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; font-weight: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">* Hash_DRBG
* HMAC_DRBG
* CTR_DRBG
</code></pre>
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
So there you go. Those three algorithms are CSPRNG because they've been tested and recommended by the NIST*.</div>
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
*There are other organizations and tests that determine a PRNG to be a CSPRNG, but the NIST is the 800-pound Gorilla.</div>
</h1>
<h2 style="background-color: white; border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">
Controversy</h2>
<h1 style="background-color: white; border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em;">
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
It's worth noting that the original publication actually had 4 CSPRNG recommendations. The now infamous <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;"><a href="https://en.wikipedia.org/wiki/Dual_EC_DRBG">Dual_EC_DRBG</a></code> was quietly removed in the revised publication SP800-9Ar1.</div>
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px; margin-bottom: 16px;">
There has been a lot of controversy[<a href="https://www.schneier.com/blog/archives/2007/11/the_strange_sto.html">1</a>][<a href="http://blog.cryptographyengineering.com/2015/01/hopefully-last-post-ill-ever-write-on.html">2</a>] surrounding <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">Dual_EC_DRBG</code>. Whether or not any of the controversy is true, it's clear that trust in the NIST's authority has been undermined by its recommendation of <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">Dual_EC_DRBG</code>. I'm grateful that the NIST has removed the algorithm from its newest revision.</div>
<div style="box-sizing: border-box; font-size: 14px; font-weight: normal; line-height: 22.4px;">
This also serves as a warning to anyone trying to influence these types of publications. The people that design, implement and critique this type of cryptography are smart. Very smart. Smarter than you and me -- and they don't like shenanigans!</div>
</h1>
<div>
<span style="font-family: "times" , "times new roman" , serif;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/6b0ftfKFEJg/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/6b0ftfKFEJg?feature=player_embedded" width="320"></iframe></div>
<span style="font-family: "times" , "times new roman" , serif;"><br /></span></div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com1tag:blogger.com,1999:blog-2870713865752955687.post-50164321462531244742015-07-20T20:08:00.001-07:002015-07-24T12:52:31.293-07:00Try patch instead of sed in shell scripts<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 0px !important; position: relative;">
A script is better seen than sed</h3>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
I'd like to offer all of the shell scripters out there an alternative to sed replacements: patch.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
Patch has several important benefits:</div>
<ul style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px; margin-top: 0px; padding: 0px 0px 0px 2em;">
<li style="box-sizing: border-box;">Context for all changes</li>
<li style="box-sizing: border-box;">Easy backup via the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; margin: 0px; padding: 0.2em 0px;">-b</code> flag</li>
<li style="box-sizing: border-box;">Easy rollback</li>
<li style="box-sizing: border-box;">Easy multi-line replacements</li>
</ul>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
Sed is great but can often times lead to enigmatic behavior. This is especially true when using wildcard expressions or other shell magic. And as the saying goes, code is read more often than it is written, so you should write for readability.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
Here's a common type of sed replacement you'll find in any old off-the-shelf shell script:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"># Replace some mystery var with this one
sed -i 's/setting_foo: */setting_foo: 5'
</code></pre>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
This kind of thing makes sense to the author, but the reader is at a disadvantage. What is the original value of setting_foo? What type of setting is it and why change it? These are things that are lost in translation with these commands.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
And it can easily and often times be worse:</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">sed -ie 's/[]\/$*.^|[]/\\&/g' file
</code></pre>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
Here's a real example of updating a mysql.conf. Since multiple lines potentially start with port, you need to use a regular expression to match the word and whitespace to prevent accidents. Also, it's difficult to maintain the original justification of the file. And who knows what the original values were</div>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; font-stretch: normal; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"># Change the port. Since this argument appears on several lines, we only want to change the first one
sed -ie '0,/^port\s*=\s*/port = 8000/' /etc/mysql
# Change port using whitespace
sed -i 's/max_allowed_packet = 16M/max_allowed_packet = 32M/' /etc/mysql
# Allow more packets
sed -ie 's/^max_allowed_packet\s*=*/max_allowed_packet = 32M/' /etc/mysql.conf
</code></pre>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
Pretty ugly.</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
Now compare these same changes with patch</div>
<div class="highlight highlight-patch" style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px; overflow: visible !important;">
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; font-stretch: normal; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">patch -b /etc/mysql.conf <<PATCH
<span class="pl-md" style="background-color: #ffecec; box-sizing: border-box; color: #bd2c00;">--- mysql.conf_old 2015-07-20 19:53:25.000000000 -0700</span>
<span class="pl-mi1" style="background-color: #eaffea; box-sizing: border-box; color: #55a532;">+++ mysql.conf 2015-07-20 19:58:28.000000000 -0700</span>
<span class="pl-mdr" style="box-sizing: border-box; color: #795da3; font-weight: bold;">@@ -8,14 +8,14 @@</span>
[client]
<span class="pl-md" style="background-color: #ffecec; box-sizing: border-box; color: #bd2c00;">-port = 3306</span>
<span class="pl-mi1" style="background-color: #eaffea; box-sizing: border-box; color: #55a532;">+port = 8000</span>
socket = /var/run/mysqld/mysql.sock
[mysql]
no_auto_rehash
<span class="pl-md" style="background-color: #ffecec; box-sizing: border-box; color: #bd2c00;">-max_allowed_packet = 16M</span>
<span class="pl-mi1" style="background-color: #eaffea; box-sizing: border-box; color: #55a532;">+max_allowed_packet = 32M</span>
prompt = '\u@\h [\d]> '
default_character_set = utf8 # Possibly this setting is correct for most recent Linux systems
PATCH</pre>
</div>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px; margin-bottom: 16px;">
<br />
Clean and simple! You can see we've obviously added more lines to the script, but we have context to our changes. We've also used the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; margin: 0px; padding: 0.2em 0px;">-b</code> flag to automatically backup the file.</div>
<h3 style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
Closing thoughts</h3>
<div style="background-color: white; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 14px; line-height: 22.3999996185303px;">
Of course this isn't always ideal. A good example is when you don't actually know the value that you're replacing. But nevertheless I think it's a good alternative that should be used when readability is important.</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-38069358128157443342015-02-28T09:35:00.001-08:002015-05-13T09:07:17.951-07:00List running EC2 instances with golang and the aws-sdk-go<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Managing multiple AWS accounts can sometimes be tough, even when doing something as simple as matching a private IP address with a hostname.<br />
<br />
In the past I used the aws cli tools, but I had to constantly switch both the accounts and the regions when making requests:<br />
<br />
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: 1.45; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;"># Make it's in the prod-5 account in us-west-1
aws ec2 --profile=prod-5 --region=us-west-1 | grep my_instance
# Okay not that account or region, let's try eu-west-1
aws ec2 --profile=prod-5 --region=eu-west-2 | grep my_instance
Repeat 1x for each account and region</code></pre>
<br />
As you can imagine this is extremely time consuming, even when using the CLI tools. <span style="line-height: 25.6000003814697px;">I wrote a small tool that will find every single instance you can view using every account available to you (according to your ~/.aws/config). The aggregate results can then be searched.</span><br />
<span style="line-height: 25.6000003814697px;"><br /></span>
<span style="line-height: 25.6000003814697px;">I choose to use the existing ~/.aws/config file so that it works along side your normal aws cli tools. </span><br />
<br />
This is a very good use-case for Golang, which has nice concurrency primitives. With five accounts this script (once compiled) will display all of the results in under 1.5 seconds. Not bad.<br />
<br />
The result is a space-separated list with some additional values added. It should be easy to find what you're looking for:<br />
<br />
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: 1.45; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: inherit; margin: 0px; max-width: initial; overflow: initial; padding: 0px; word-break: normal; word-wrap: normal;">$ ./aws_list
i-71930187 prod-manage005 10.0.0.180 t2.micro 207.171.166.22 prod-account
i-71930187 stage-controller7 10.0.0.164 t2.medium 72.21.206.80 staging-account
i-71930187 prod-vpn01 10.0.0.239 m4.large None prod-account
i-71930187 stephen-test-host 10.0.0.216 m3.large 216.58.216.174 test-account
...</code></pre>
<br />
The output is a space-separated file and only "running" and "pending" instances are displayed. <span style="line-height: 25.6000003814697px;">For a list of filters or instance attributes consult the </span><a href="http://godoc.org/github.com/awslabs/aws-sdk-go/gen/ec2#Instance" rel="noreferrer" style="box-sizing: border-box; color: #4183c4; line-height: 25.6000003814697px; text-decoration: none;">official documentation</a><span style="line-height: 25.6000003814697px;">.</span><br />
<span style="line-height: 25.6000003814697px;"><br /></span>
<span style="line-height: 25.6000003814697px;"></span><br />
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.8999996185303px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">package</span> main
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">import</span> (
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>fmt<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/awslabs/aws-sdk-go/aws<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/awslabs/aws-sdk-go/service/ec2<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>github.com/vaughan0/go-ini<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>net/url<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>os<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>runtime<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>strings<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>sync<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
)
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #795da3;">check</span>(<span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">e</span> <span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">error</span>) {
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">if</span> e != <span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">nil</span> {
<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">panic</span>(e)
}
}
<span class="pl-c" style="box-sizing: border-box; color: #969896;">/*</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">printIds accepts an aws credentials file and a region, and prints out all</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">instances within the region in a format that's acceptable to us. Currently that</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">format is like this:</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;"></span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;"> instance_id name private_ip instance_type public_ip account</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;"></span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">Any values that aren't available (such as public ip) will be printed out as</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">"None"</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;"></span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">Because the "name" parameter is user-defined, we'll run QueryEscape on it so that</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">our output stays as a space-separated line.</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">*/</span>
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #795da3;">printIds</span>(<span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">creds</span> <span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">aws</span>.<span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">CredentialsProvider</span>, <span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">account</span> <span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">string</span>, <span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">region</span> <span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">string</span>, <span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">wg</span> *<span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">sync</span>.<span class="pl-v" style="box-sizing: border-box; color: #1d3e81;">WaitGroup</span>) {
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">defer</span> wg.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Done</span>()
<span class="pl-vo" style="box-sizing: border-box;">svc</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> ec2.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">New</span>(&aws.<span class="pl-vo" style="box-sizing: border-box;">Config</span>{
Credentials: creds,
Region: region,
})
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Here we create an input that will filter any instances that aren't either</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// of these two states. This is generally what we want</span>
<span class="pl-vo" style="box-sizing: border-box;">params</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> &ec2.<span class="pl-vo" style="box-sizing: border-box;">DescribeInstancesInput</span>{
Filters: []*ec2.<span class="pl-vo" style="box-sizing: border-box;">Filter</span>{
&ec2.<span class="pl-vo" style="box-sizing: border-box;">Filter</span>{
Name: aws.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">String</span>(<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>instance-state-name<span class="pl-pds" style="box-sizing: border-box;">"</span></span>),
Values: []*<span class="pl-st" style="box-sizing: border-box; color: #a71d5d;">string</span>{
aws.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">String</span>(<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>running<span class="pl-pds" style="box-sizing: border-box;">"</span></span>),
aws.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">String</span>(<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>pending<span class="pl-pds" style="box-sizing: border-box;">"</span></span>),
},
},
},
}
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// TODO: Actually care if we can't connect to a host</span>
<span class="pl-vo" style="box-sizing: border-box;">resp</span>, <span class="pl-vo" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> svc.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">DescribeInstances</span>(params)
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// if err != nil {</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// panic(err)</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// }</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Loop through the instances. They don't always have a name-tag so set it</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// to None if we can't find anything.</span>
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">for</span> <span class="pl-vo" style="box-sizing: border-box;">idx</span>, <span class="pl-vo" style="box-sizing: border-box;">_</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">range</span> resp.<span class="pl-vo" style="box-sizing: border-box;">Reservations</span> {
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">for</span> <span class="pl-vo" style="box-sizing: border-box;">_</span>, <span class="pl-vo" style="box-sizing: border-box;">inst</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">range</span> resp.<span class="pl-vo" style="box-sizing: border-box;">Reservations</span>[idx].<span class="pl-vo" style="box-sizing: border-box;">Instances</span> {
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// We need to see if the Name is one of the tags. It's not always</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// present and not required in Ec2.</span>
<span class="pl-vo" style="box-sizing: border-box;">name</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>None<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">for</span> <span class="pl-vo" style="box-sizing: border-box;">_</span>, <span class="pl-vo" style="box-sizing: border-box;">keys</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">range</span> inst.<span class="pl-vo" style="box-sizing: border-box;">Tags</span> {
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">if</span> *keys.<span class="pl-vo" style="box-sizing: border-box;">Key</span> == <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>Name<span class="pl-pds" style="box-sizing: border-box;">"</span></span> {
name = url.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">QueryEscape</span>(*keys.<span class="pl-vo" style="box-sizing: border-box;">Value</span>)
}
}
<span class="pl-vo" style="box-sizing: border-box;">important_vals</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> []*<span class="pl-st" style="box-sizing: border-box; color: #a71d5d;">string</span>{
inst.<span class="pl-vo" style="box-sizing: border-box;">InstanceID</span>,
&name,
inst.<span class="pl-vo" style="box-sizing: border-box;">PrivateIPAddress</span>,
inst.<span class="pl-vo" style="box-sizing: border-box;">InstanceType</span>,
inst.<span class="pl-vo" style="box-sizing: border-box;">PublicIPAddress</span>,
&account,
}
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Convert any nil value to a printable string in case it doesn't</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// doesn't exist, which is the case with certain values</span>
<span class="pl-vo" style="box-sizing: border-box;">output_vals</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> []<span class="pl-st" style="box-sizing: border-box; color: #a71d5d;">string</span>{}
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">for</span> <span class="pl-vo" style="box-sizing: border-box;">_</span>, <span class="pl-vo" style="box-sizing: border-box;">val</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">range</span> important_vals {
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">if</span> val != <span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">nil</span> {
output_vals = <span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">append</span>(output_vals, *val)
} <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">else</span> {
output_vals = <span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">append</span>(output_vals, <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>None<span class="pl-pds" style="box-sizing: border-box;">"</span></span>)
}
}
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// The values that we care about, in the order we want to print them</span>
fmt.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Println</span>(strings.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Join</span>(output_vals, <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span> <span class="pl-pds" style="box-sizing: border-box;">"</span></span>))
}
}
}
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">func</span> <span class="pl-en" style="box-sizing: border-box; color: #795da3;">main</span>() {
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Go for it!</span>
runtime.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">GOMAXPROCS</span>(runtime.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">NumCPU</span>())
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Make sure the config file exists</span>
<span class="pl-vo" style="box-sizing: border-box;">config</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> os.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Getenv</span>(<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>HOME<span class="pl-pds" style="box-sizing: border-box;">"</span></span>) + <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>/.aws/config<span class="pl-pds" style="box-sizing: border-box;">"</span></span>
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">if</span> <span class="pl-vo" style="box-sizing: border-box;">_</span>, <span class="pl-vo" style="box-sizing: border-box;">err</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> os.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Stat</span>(config); os.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">IsNotExist</span>(err) {
fmt.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Println</span>(<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>No config file found at: <span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">%s</span><span class="pl-pds" style="box-sizing: border-box;">"</span></span>, config)
os.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Exit</span>(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">1</span>)
}
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">var</span> <span class="pl-vo" style="box-sizing: border-box;">wg</span> sync.<span class="pl-vo" style="box-sizing: border-box;">WaitGroup</span>
<span class="pl-vo" style="box-sizing: border-box;">file</span>, <span class="pl-vo" style="box-sizing: border-box;">err</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> ini.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">LoadFile</span>(config)
<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">check</span>(err)
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">for</span> <span class="pl-vo" style="box-sizing: border-box;">key</span>, <span class="pl-vo" style="box-sizing: border-box;">values</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">range</span> file {
<span class="pl-vo" style="box-sizing: border-box;">profile</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> strings.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Fields</span>(key)
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Don't print the default or non-standard profiles</span>
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">if</span> <span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">len</span>(profile) != <span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">2</span> {
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">continue</span>
}
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Where to find this host. The account isn't necessary for the creds</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// but it's something we expose to users when we print</span>
<span class="pl-vo" style="box-sizing: border-box;">account</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> profile[<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">1</span>]
<span class="pl-vo" style="box-sizing: border-box;">key</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> values[<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>aws_access_key_id<span class="pl-pds" style="box-sizing: border-box;">"</span></span>]
<span class="pl-vo" style="box-sizing: border-box;">pass</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> values[<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>aws_secret_access_key<span class="pl-pds" style="box-sizing: border-box;">"</span></span>]
<span class="pl-vo" style="box-sizing: border-box;">creds</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> aws.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Creds</span>(key, pass, <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span><span class="pl-pds" style="box-sizing: border-box;">"</span></span>)
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Gather a list of all available AWS regions. Even though we're gathering</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// all regions, we still must use a region here for api calls.</span>
<span class="pl-vo" style="box-sizing: border-box;">svc</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> ec2.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">New</span>(&aws.<span class="pl-vo" style="box-sizing: border-box;">Config</span>{
Credentials: creds,
Region: <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>us-west-1<span class="pl-pds" style="box-sizing: border-box;">"</span></span>,
})
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Iterate over every single stinking region to get a list of available</span>
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// ec2 instances</span>
<span class="pl-vo" style="box-sizing: border-box;">regions</span>, <span class="pl-vo" style="box-sizing: border-box;">err</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> svc.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">DescribeRegions</span>(&ec2.<span class="pl-vo" style="box-sizing: border-box;">DescribeRegionsInput</span>{})
<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">check</span>(err)
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">for</span> <span class="pl-vo" style="box-sizing: border-box;">_</span>, <span class="pl-vo" style="box-sizing: border-box;">region</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">:=</span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">range</span> regions.<span class="pl-vo" style="box-sizing: border-box;">Regions</span> {
wg.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Add</span>(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">1</span>)
<span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">go</span> <span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">printIds</span>(creds, account, *region.<span class="pl-vo" style="box-sizing: border-box;">RegionName</span>, &wg)
}
}
<span class="pl-c" style="box-sizing: border-box; color: #969896;">// Allow the goroutines to finish printing</span>
wg.<span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">Wait</span>()
}</pre>
</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com1tag:blogger.com,1999:blog-2870713865752955687.post-61240897148058275072015-02-25T21:46:00.000-08:002015-02-26T09:34:04.776-08:00Generate a unique, strong password on the command line (linux, mac osx)<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Find yourself generating a lot of random passwords? Here's a way to generate quick, random, and secure passwords on the command line:</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">echo</span> <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">$(</span>head -c 64 /dev/urandom <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">|</span> base64<span class="pl-pds" style="box-sizing: border-box;">)</span></span> <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">$(</span>date +%s<span class="pl-pds" style="box-sizing: border-box;">)</span></span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">|</span> shasum <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">|</span> awk <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">'</span>{print $1}<span class="pl-pds" style="box-sizing: border-box;">'</span></span></pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
This command will read 64 bytes of random data from /dev/urandom, base64 encode it, add a small salt (the current data in epoch time), and then create a sha1 hash of the data.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
I like this because it's cryptographically secure and the chance of a collision (provided your PNRG isn't totally borked), is infinitely small. It's also a hexadecimal string, so I don't have to worry about quoting it in weird ways or escaping special characters. I can just double-click it in iterm and it's automatically added to my clipboard!<br />
<br />
Go ahead and double click the shas below and then click the password from 1password. You'll know what I'm talking about.<br />
<br />
The drawback being you can't possibly remember these passwords unless you're <a href="http://news.yahoo.com/blogs/sideshow/u-s--memory-champion-nelson-dellis-shares-his-secrets-for-strengthening-your-mind-194920556.html">US memory champion Nelson Dellis</a>, but you use a password manager anyway, right? Right?!</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
I do this so frequently that I created an alias, so I just have to type "pw" on the command line to get a random password.</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="pl-s3" style="box-sizing: border-box; color: #0086b3;">alias</span> pw=<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-pds" style="box-sizing: border-box;">"</span>echo <span class="pl-cce" style="box-sizing: border-box;">\$</span>(head -c 64 /dev/urandom | base64) <span class="pl-cce" style="box-sizing: border-box;">\$</span>(date +%s) | shasum | awk '{print <span class="pl-cce" style="box-sizing: border-box;">\$</span>1}'<span class="pl-pds" style="box-sizing: border-box;">"</span></span></pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Now you can create random passwords all day long.</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;">[stephen </span></span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">~</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;">]$ pw
fc2bff4a44cc71b77638185161383592adcf5a6d
[stephen </span></span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">~</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;">]$ pw
172f09a28878eab53df26801564f164209da7b6e
[stephen </span></span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">~</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;">]$ </span></span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">while</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;"> </span></span><span class="pl-s3" style="box-sizing: border-box; color: #0086b3; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">true</span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">;</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;"> </span></span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">do</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;"> pw</span></span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">;</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;"> </span></span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.6000003814697px; line-height: 1.45;">done</span><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;">
cf8f04bfa23b16dea92b69a9af72a0433e67cb79
28219dc9f626233df6361b44c673505755ac380e
ce14392eeeb408d68a4436586fc05f691c334006
d9c82dd59637ee75d9090195a4633d4b184e6e65
26e6754f480cf039d6b0e131bf079b2a0338b3e2
75376f012bc2ff36c00cb224ac245da719c832ae
b530a231f3a60030db47c077a249857ce4bb2d45
...</span></span></pre>
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span style="font-family: Consolas, Liberation Mono, Menlo, Courier, monospace;"><span style="font-size: 13.6000003814697px; line-height: 1.45;"># Here's a password from 1password. Go ahead and double click it to add it to your clipboard
</span><span style="font-size: 13.6000003814697px; line-height: 19.7199993133545px;">Fp9ef>btgMUm%K2AokM(JXV,vkF?CGX9Ry4d78.a</span></span></pre>
</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-72944939252836901292014-11-22T12:55:00.002-08:002019-07-16T15:12:19.607-07:00Encrypting and decrypting files with Gnu Privacy Guard (GPG)<div dir="ltr" style="text-align: left;" trbidi="on">
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
Asymmetrical encryption with GnuPG</h1>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://gnupg.org/share/logo-gnupg-light-purple-bg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://gnupg.org/share/logo-gnupg-light-purple-bg.png" height="107" width="320" /></a></div>
<br />
You should start using asymmetrical encryption for your backups. Here's a little guide.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
With asymmetrical key encryption, other hosts and people can encrypt data that only you can decrypt, meaning that you don't have to share a secret key with anyone and you can distribute the public key freely.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
At Elastica this is how we do backups. Every host gets preseeded with one of our strong backup keys. This allows them to gobble up sensitive data and store it in places like S3. If our S3 account was ever compromised then the intruder would have a bunch of encrypted files that would take them 20 years of computing power to decrypt.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Since decryption speed is not an issue with cold storage backups, I recommend the maximum 4096-bit RSA key.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Here's a quick guide to creating a strong crypto key and encrypting some files.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Also remember that gpg can be installed on your mac via <a href="http://brewformulas.org/Gnupg">brew</a>.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Generate the key:</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --gen-key
(follow the prompts)</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
If you'd rather do this automatically or in a script, you can feed the options in:</div>
<div class="highlight highlight-bash" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --batch --gen-key <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;"><<</span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">EOF</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> Key-Type: rsa</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> Key-Length: 4096</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> Name-Real: Stephen Wood</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> Name-Comment: For Testing</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> Name-Email: stephen@gmail.com</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> Expire-Date: 0</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> %pubring my_key.pub</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> %secring my_key.sec</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> %commit</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"> %echo done</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">EOF</span></span></pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
You'll want to import the private key on any hosts that you want to be able to decrypt data.</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --allow-secret-key-import --import my_key.key</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Remember to securely delete your secret key if you're not going to put the file elsewhere.</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ srm my_key.key</pre>
</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
Encrypting and decrypting</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Encrypting can be done on any host that has your public key. First, import the public key to the local hosts's gpg key ring</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --import my_key.pub</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
To encrypt a single file:</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --recipient stephen@gmail.com --encrypt ping.heystephenwood.com.cert
(creates ping.heystephenwood.com.cert.gpg)</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Note that the key is referred to as an email address. This is how gpg typically works.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Decrypting the file is easy if you have the private key:</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --decrypt ping.heystephenwood.com.cert.gpg <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">></span> ping.heystephenwood.com.cert</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
By default gpg will decrypt a file to stdout, so we redirect it to a file. You can tell gpg to decrypt it to the original filename by passing in the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin: 0px; padding: 0.2em 0px;">--use-embedded-filename</code> flag:</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --use-embedded-filename --decrypt ping.heystephenwood.com.cert.gpg
(creates ping.heystephenwood.com.cert.gpg)</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Notice that we didn't even have to specify which key to use. That's because gpg will use imbedded metadata in the file to decrypt the key. You can see this information by passing in the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin: 0px; padding: 0.2em 0px;">--list-packets</code> flag:</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">$ gpg --list-packets ping.heystephenwood.com.cert.gpg
:pubkey enc packet: version 3, algo 1, keyid 6FC17A3C5E45F65C
data: [4096 bits]
:encrypted data packet:
length: unknown
mdc_method: 2
gpg: encrypted with 4096-bit RSA key, ID 5E45F65C, created 2014-06-13
"Stephen Wood <stephen@gmail.com>"
:compressed packet: algo=2
:literal data packet:
mode b (62), created 1416686288, name="ping.heystephenwood.com.cert",
raw data: 2171 bytes
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Pretty nifty, huh?</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a class="anchor" href="https://gist.github.com/stephen-mw/c99219218fbfab0c859d#multiple-files" name="user-content-multiple-files" rel="noreferrer" style="bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Multiple files</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Encrypting multiple files is much easier to do via the tar command. Since gpg files are compressed automatically, it's not even necessary to gzip them!</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Here's how to encrypt an entire folder:</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ tar cf - some_folder <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">|</span> gpg --recipient stephen@gmail.com
(creates some_folder.gpg)</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Since gpg defaults to stdout, we simply need to pass that back to tar</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg --decrypt some_folder.gpg <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">|</span> tar xf -
(creates some_folder)</pre>
</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a class="anchor" href="https://gist.github.com/stephen-mw/c99219218fbfab0c859d#other-fun-things" name="user-content-other-fun-things" rel="noreferrer" style="bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Other fun things</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
You can also use your private key to sign a message that others can verify for authenticity.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Let's create a document:</div>
<div class="highlight highlight-bash" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">cat <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">></span> my_message.txt <span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;"><<</span><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">MESSAGE</span></span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;">Help! The NSA is after me! They've tapped my phone, TV, microwave, and</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;">Nike Air Jordans! Also the fillings in my teeth won't stop playing episodes</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;">of "This American Life" and Ira Glass is getting on my nerves.</span>
<span class="pl-s1" style="box-sizing: border-box; color: #df5000;"><span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">MESSAGE</span></span></pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Now let's sign the message:</div>
<div class="highlight highlight-shell" style="background: rgb(255, 255, 255); box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;">$ gpg -u stephen@gmail.com --clearsign my_message.txt
(produces my_message.txt.asc)</pre>
</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
You've got yourself a signed document.</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">$ cat my_message.txt.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Help! The NSA is after me! They've tapped my phone, TV, microwave, and
Nike Air Jordans! Also the fillings in my teeth won't stop playing episodes
of "This American Life" and Ira Glass is getting on my nerves.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAEBAgAGBQJUcPACAAoJEKSJEkYj0afvor0QALvrYflk52NkNmwpq09FM+2x
06RKsmzQgXa8W+3yHpTUlAMhVPoToeETp9wrM4zod+6nmiyan/aqP1QzXq0QC+yc
SEOGIn7r69+d1ybCXHnC2ebbB2pVj8NwH30a6hLNUHlmZ9xGjX4bnqUREIo1booV
MnWqUab7PFjEJ97fVW9b47kpZ+Mi0P8MhphGA+QHzGl56UtDo5wPci8A3TKqfCsq
didoYGAJurVnVIwvjXPkwKnKwL4E0AvTRN5iiiN6Rib+be8Pmy8wUNA7LdwjERO1
H8zVCgyFvOzA16PbdmKJF5nnUAlJASO4ZStUD5z/AIYir9cXuNSlx45FFVse3lFu
yyftQkvJPJbzVdg/JaYswj7vMFPPmRBweFzFZjBqrDu+o1aPWougbOFnU3ZDuf3s
4SmbI7gJDDet7cvYHWn+8doGGI5BpPb0gXjfhW+WBuvMZ01GJbXwychi5d4xC1Qi
XYkd4RgdxxIhyLrO+whWYHFZlI3UY6cPPyyiDjTLR/UCP2IrtdL7gcPJicXGSGG3
EJLjG1mK+nk44QT4oW7Ghha6G1oI2YoqjAWrlWhaSyxlNSv4qw75x5w6WtzoL2yR
mayROMUmmHrBYfgFtgk64X+qcd3Li8/InZUw95A5SnV69r2h5p05fPiE70sgu73R
ozOu9eBEjYDTEb4PYS+5
=JiEL
-----END PGP SIGNATURE-----
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Anyone can verify the message. They don't even need your public key:<br />
<br />
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">gpg --verify my_message.txt.asc
gpg: Signature made Sat Nov 22 12:29:17 2014 PST using RSA key ID 23D1A7EF
gpg: Good signature from "Stephen Wood <stephen@gmail.com>"</code></pre>
</div>
<div>
<span style="color: #333333; font-family: "helvetica neue" , "helvetica" , "segoe ui" , "arial" , "freesans" , sans-serif; font-size: 16px; line-height: 25.6000003814697px;">And what happens when somebody intercepts and alters your original message?</span></div>
<div>
<span style="color: #333333; font-family: "helvetica neue" , "helvetica" , "segoe ui" , "arial" , "freesans" , sans-serif; font-size: 16px; line-height: 25.6000003814697px;"><br /></span></div>
<div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">$ cat my_message.txt.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Dear friend. All is well here.
-----BEGIN PGP SIGNATURE-----
...</code></pre>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">gpg --verify my_message.txt.asc
gpg: Signature made Sat Nov 22 12:20:18 2014 PST using RSA key ID 23D1A7EF
gpg: BAD signature from "Stephen Wood <stephen@gmail.com>"
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
Looks like your friend is dead. I'm so sorry.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
This can be taken a step further if you've already securely exchanged your public key with your "friend". They can both verify your message hasn't been altered, and also verify that it was sent from you. They just need to verify that the Key ID is the same as the one you've imported.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px;">
That's it for now. Encrypt your backups! It's easy to do.</div>
</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-62479334477806304402014-09-29T10:08:00.003-07:002015-01-24T16:59:46.434-08:00OpenVPN & Raspberry Pi auto-installer<div dir="ltr" style="text-align: left;" trbidi="on">
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
Openvpn server on your Raspberry PI</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
<div class="separator" style="clear: both; text-align: left;">
<a href="https://travis-ci.org/stephen-mw/raspberrypi-openvpn-auto-install.svg?branch=add-travis-support" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://travis-ci.org/stephen-mw/raspberrypi-openvpn-auto-install.svg?branch=add-travis-support" /></a></div>
<br />
From wikipedia:</div>
<blockquote style="border-left-color: rgb(221, 221, 221); border-left-style: solid; border-left-width: 4px; box-sizing: border-box; color: #777777; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin: 0px 0px 16px; padding: 0px 15px;">
<div style="box-sizing: border-box;">
OpenVPN is an open source software application that implements virtual private network (VPN) techniques for creating secure point-to-point or site-to-site connections in routed or bridged configurations and remote access facilities. It uses a custom security protocol that utilizes SSL/TLS for key exchange.</div>
</blockquote>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
What that means is that openvpn will allow you to safely and securely route your internet traffic through an untrusted network to a trusted one. It does this by encrypting your traffic so nobody can read it until it goes out from your openvpn server.</div>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
There are some benefits to this:</div>
<ol class="task-list" style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px; margin-top: 0px; padding: 0px 0px 0px 2em;">
<li style="box-sizing: border-box;">Prevent others from snooping on your traffic.</li>
<li style="box-sizing: border-box;">Access websites that are blocked by your work, school, or oppressive governments.</li>
<li style="box-sizing: border-box;">Access assets on your home network from anywhere.</li>
</ol>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
This auto-install script will turn your raspberry pi into an openvpn server so you can browse the internet safely and securely.</div>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
Then why use it? Because sometimes you end up on insecure networks (think starbucks, stadiums, etc). This will protect your privacy in those situations. It will not prevent people from finding you if you are stupid and do something illegal.</div>
</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/raspberrypi-openvpn-auto-install/tree/master#running-the-installer" name="user-content-running-the-installer" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Running the installer</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
The auto-installer is completely automated and can be run directly from the web.</div>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
From your raspberry pi:</div>
<div class="highlight highlight-bash" style="background: rgb(255, 255, 255); box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="c" style="box-sizing: border-box; color: #999988; font-style: italic;"># Set the user</span>
<span class="nv" style="box-sizing: border-box; color: teal;">$ OPENVPN_USER</span><span class="o" style="box-sizing: border-box; font-weight: bold;">=</span><span class="s1" style="box-sizing: border-box; color: #dd1144;">'stephen.openvpn.local'</span>
<span class="c" style="box-sizing: border-box; color: #999988; font-style: italic;"># Run the installer</span>
<span class="nv" style="box-sizing: border-box; color: teal;">$ </span>curl <span class="s2" style="box-sizing: border-box; color: #dd1144;">"https://raw.githubusercontent.com/stephen-mw/raspberrypi-openvpn-autoinstall/master/bootstrap"</span> <span class="p" style="box-sizing: border-box;">|</span> sudo bash
</pre>
</div>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
<br />
The default key size is 4096 bits long. You can change the key size by exporting the KEY_SIZE variable before running the installer:<br />
<br />
<pre style="background-color: #f7f7f7; border-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; font-weight: bold; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="c" style="box-sizing: border-box; color: #999988; font-style: italic;"># Change the key size to something other than 4096</span>
<span class="nv" style="box-sizing: border-box; color: teal;">$ KEY_SIZE=2048</span>
</pre>
<div>
<span class="s1" style="box-sizing: border-box; color: #dd1144;"><div style="color: black; font-size: 16.3636360168457px; line-height: 23.2727279663086px;">
<br /></div>
<div style="color: black; font-size: 16.3636360168457px; line-height: 23.2727279663086px;">
Remember that you should always inspect these types of files before ever running them. You can download it locally and run it like so:</div>
</span></div>
</div>
<div class="highlight highlight-bash" style="background: rgb(255, 255, 255); box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="c" style="box-sizing: border-box; color: #999988; font-style: italic;"># Download the file</span>
<span class="nv" style="box-sizing: border-box; color: teal;">$ </span>wget <span class="s2" style="box-sizing: border-box; color: #dd1144;">"https://raw.githubusercontent.com/stephen-mw/raspberrypi-openvpn-autoinstall/master/bootstrap"</span>
<span class="c" style="box-sizing: border-box; color: #999988; font-style: italic;"># Make sure it's legit</span>
<span class="nv" style="box-sizing: border-box; color: teal;">$ </span>less bootstrap
<span class="c" style="box-sizing: border-box; color: #999988; font-style: italic;"># Execute it</span>
<span class="nv" style="box-sizing: border-box; color: teal;">$ </span>chmod +x bootstrap
<span class="nv" style="box-sizing: border-box; color: teal;">$ </span>sudo ./bootstrap stephen.openvpn.local
</pre>
</div>
</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/raspberrypi-openvpn-auto-install/tree/master#whats-the-installer-do" name="user-content-whats-the-installer-do" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>What's the installer do</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
The installer script will download openvpn and generate all of the necessary root certificates for you. Then it will generate and sign a new certificate for a user. Lastly it will create the ovpn file and place it in <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">/root/client_<some_user></code>.</div>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
All you need to do is download that file into your openvpn client software and you'll be able to safely and securely connect to the host.</div>
</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/raspberrypi-openvpn-auto-install/tree/master#testing" name="user-content-testing" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Testing</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; margin-bottom: 16px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
I've included a Vagrantfile for you to run tests. Simply clone the repo and then run:</div>
<div class="highlight highlight-bash" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px; margin-bottom: 16px;">
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"><span class="nv" style="box-sizing: border-box; color: teal;">$ </span>vagrant <span class="nv" style="box-sizing: border-box; color: teal;">up</span>
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: Forcing shutdown of VM...
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: Destroying VM and associated drives...
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: Running cleanup tasks <span class="k" style="box-sizing: border-box; font-weight: bold;">for</span> <span class="s1" style="box-sizing: border-box; color: #dd1144;">'shell'</span> provisioner...
Bringing machine <span class="s1" style="box-sizing: border-box; color: #dd1144;">'default'</span> up with <span class="s1" style="box-sizing: border-box; color: #dd1144;">'virtualbox'</span> provider...
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: Importing base box <span class="s1" style="box-sizing: border-box; color: #dd1144;">'wheezy64'</span>...
...
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: Make sure that your firewall allows incoming UDP connections to port 1194.
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default:
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: The last thing necessary is to securely copy the configuration file over to <span class="nv" style="box-sizing: border-box; color: teal;">your</span>
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: computer and <span class="k" style="box-sizing: border-box; font-weight: bold;">then</span> load it. The configuration file is located at:
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default:
<span class="o" style="box-sizing: border-box; font-weight: bold;">==</span>> default: /root/client_test.ovpn
</pre>
</div>
<div style="box-sizing: border-box;">
<div style="color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; font-weight: normal; line-height: 23.2727279663086px;">
The vagrant guest will be running the openvpn server. You can pull down the client file and connect to it locally.</div>
</div>
</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
Clone the repo</h2>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; margin-bottom: 16px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
<div style="box-sizing: border-box;">
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="font-size: 16px; font-weight: normal; line-height: 23.2727279663086px;"><a href="https://github.com/stephen-mw/raspberrypi-openvpn-auto-install">https://github.com/stephen-mw/raspberrypi-openvpn-auto-install</a></span></span><br />
<br />
Edit: 2014-12-23<br />
<span style="font-size: small;"><br />The original bootstrap was missing some iptables rules that allowed the raspberry pi to masquarade and forward IP. I've updated the script and everything should be working out of the box now.</span></div>
</h2>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com10tag:blogger.com,1999:blog-2870713865752955687.post-80247840452034407942014-09-23T11:10:00.004-07:002014-09-23T11:10:54.509-07:00Mac OS X time machine backups to a windows or linux samba share<div dir="ltr" style="text-align: left;" trbidi="on">
Time machine is a great product from Apple. I used it just recently when I replaced my laptop. All I had to do was select the time machine disk when booting up for the first time and everything was just how I left it. Fantastic!<br />
<br />
Creating backups is now very important to me. With a USB hard drive this is very simple, but I wanted to take backups to my home server, where there is plenty of secure space.<br />
<br />
Making a backup to network drives (like windows and linux samba shares) is not supported out of the box. I'll show you how to do it.<br />
<h3 style="text-align: left;">
Setting up the network drive</h3>
This guide assumes you have a network-attached drive that's available and mounted. You can use samba to create this drive on either windows or linux.<br />
<h3>
Creating the sparse disk</h3>
A sparse image is an image that grows in size. It's a mac thing. This image will become our dmg file that gets mounted.<br />
<br />
Open up up the disk utility. You can do this by searching for it in finder:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdBSVxDltriJ0Q9EMtRmMzInR5_UNvXpc5OjowW6gc_JBC_i2Yne82FWau8NMevt76CDUvdMpgkjr1GscDkzzZcudL2VMwpEbW-RQ1WvdqzLjOg3e14XptlOg4lxr0Xj0tc-wbYnPjUO0/s1600/Screen+Shot+2014-09-13+at+4.30.17+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdBSVxDltriJ0Q9EMtRmMzInR5_UNvXpc5OjowW6gc_JBC_i2Yne82FWau8NMevt76CDUvdMpgkjr1GscDkzzZcudL2VMwpEbW-RQ1WvdqzLjOg3e14XptlOg4lxr0Xj0tc-wbYnPjUO0/s1600/Screen+Shot+2014-09-13+at+4.30.17+PM.png" /></a></div>
<br />
<ul style="text-align: left;">
<li>Give it a name with something you'll remember</li>
<li>Before you do anything else, change the image format to "sparse disk image". This will allow us to create a 300GB disk image without allocating all of that space at once.</li>
<li>For format select "Mac OS extended"</li>
<li>For size select "custom" and put in your desired size. The image will grow to this size.</li>
<li>For partition select "single partition -- apple partition map"</li>
<li>Save it to your network network mount</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUAVNhg39721iQ5yvi7cNmWJA8WAfX_t2ClEdwR7aDAE7WGRzPVoGlbPaWNfbiyb6UkCqwEQUngTdwaeJIvb8_c-HPoP1ymiVeheyd2ACycvFyoC1cocBksSW9MJas77nRhHguVFFIgwc/s1600/Screen+Shot+2014-09-13+at+4.32.15+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUAVNhg39721iQ5yvi7cNmWJA8WAfX_t2ClEdwR7aDAE7WGRzPVoGlbPaWNfbiyb6UkCqwEQUngTdwaeJIvb8_c-HPoP1ymiVeheyd2ACycvFyoC1cocBksSW9MJas77nRhHguVFFIgwc/s1600/Screen+Shot+2014-09-13+at+4.32.15+PM.png" /></a></div>
<br />
You'll see that the disk is 300GB (or whatever size) large but you're only using around 300MB of it.<br />
<br />
Next we need to run a command that will force time machine to use our new disk. Find the mount point for the disk. If you select the disk in disk utilities, you can find it at the bottom. In my case it's "/Volumes/stephen_time"<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpeLc0bHf-QNrez_KJAJc1R-sqo-Dez3n66Gtb_T180HGZsW6w9CQySm16s8QC827z4fm8jAdJUYSJmF4Yo9asOKv1n80tg1baDiwhqe3JMp8GdkqfI7_f-AEU5WJQzm3RfJtrmrpc1wA/s1600/Screen+Shot+2014-09-13+at+4.39.38+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpeLc0bHf-QNrez_KJAJc1R-sqo-Dez3n66Gtb_T180HGZsW6w9CQySm16s8QC827z4fm8jAdJUYSJmF4Yo9asOKv1n80tg1baDiwhqe3JMp8GdkqfI7_f-AEU5WJQzm3RfJtrmrpc1wA/s1600/Screen+Shot+2014-09-13+at+4.39.38+PM.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYo-2QB0zagfoeg1_wV2hRRvKEZs8jyN9ADKHPJYcvEGfafZ1U8phMWQD6VMh1JlDSQQ_C4PHYjzPAXK-6PXUIO0sxNZXZ7NDmk9j2qZXYHFYC_ADtJ2Y8c1JRD3MJpn0efPcDszQ1xYI/s1600/Screen+Shot+2014-09-13+at+4.39.13+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYo-2QB0zagfoeg1_wV2hRRvKEZs8jyN9ADKHPJYcvEGfafZ1U8phMWQD6VMh1JlDSQQ_C4PHYjzPAXK-6PXUIO0sxNZXZ7NDmk9j2qZXYHFYC_ADtJ2Y8c1JRD3MJpn0efPcDszQ1xYI/s1600/Screen+Shot+2014-09-13+at+4.39.13+PM.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Open up your terminal and paste in the following command:<br />
<br />
sudo tmutil setdestination <mount point><br />
<br />
Now open up your time machine preferences and check out the new disk:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmcgW7r6Rj-R1fxkIggYoYAaaC92X1c0UOrl_93u_ZF_xbNlr9RqiPPQy0nc_hWUE8ITzqfwMBm4EWTpGrSE-w_2F2HJZiJdbs-j4zJ8keh78jc9A0NpjOYn6MTvooZNADmoWWnHXrXZM/s1600/Screen+Shot+2014-09-13+at+4.42.03+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmcgW7r6Rj-R1fxkIggYoYAaaC92X1c0UOrl_93u_ZF_xbNlr9RqiPPQy0nc_hWUE8ITzqfwMBm4EWTpGrSE-w_2F2HJZiJdbs-j4zJ8keh78jc9A0NpjOYn6MTvooZNADmoWWnHXrXZM/s1600/Screen+Shot+2014-09-13+at+4.42.03+PM.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKsaFqPTox2AWhxMIJJW9kNtr455mxPbqcGv1a8Ewk3TSHH0aJBEIXaYNSO6DlVHCMxD4vKhfrTx90y9xlJ6dJ79W5KMNT_1bXI6WqrHl28NAP6Dd_6_d2cPDxxH8DPiqCMXMHderuORQ/s1600/Screen+Shot+2014-09-13+at+4.42.17+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKsaFqPTox2AWhxMIJJW9kNtr455mxPbqcGv1a8Ewk3TSHH0aJBEIXaYNSO6DlVHCMxD4vKhfrTx90y9xlJ6dJ79W5KMNT_1bXI6WqrHl28NAP6Dd_6_d2cPDxxH8DPiqCMXMHderuORQ/s1600/Screen+Shot+2014-09-13+at+4.42.17+PM.png" height="122" width="320" /></a></div>
<br />
Hurray! You've got your disk loaded and ready to use. Now just do the backups as normal. You'll need to remount the disk (find it and double click it) when you want to make backups.<br />
<br /></div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com1tag:blogger.com,1999:blog-2870713865752955687.post-18600816387925853342014-09-22T09:53:00.005-07:002015-06-12T12:55:08.991-07:00Dyn DNS cli tool<div dir="ltr" style="text-align: left;" trbidi="on">
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif; font-size: small;"><span style="line-height: 54px;">Get the file: <a href="https://github.com/stephen-mw/dyncli">https://github.com/stephen-mw/dyncli</a></span></span></h1>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/dyncli#usage" name="user-content-usage" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Usage</h3>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">usage: dyncli [-h] [-e ENDPOINT] [-c CREATE] [--cname] [-v VALUE] [-t TTL]
[-d DELETE] [-u UPDATE_RECORD] [-U USER] [-P PASSWORD]
[-A ACCOUNT] [-Z ZONE] [-l] [--verbose]
optional arguments:
-h, --help show this help message and exit
-e ENDPOINT, --endpoint ENDPOINT
The endpoint to make API requests.
-c CREATE, --create CREATE
Create a new record. Defaults to A record unless
--cname is set.
--cname Create a cname record instead of an A record.
-v VALUE, --value VALUE
The value to set the DNS record to. Eg 10.0.0.101.
-t TTL, --ttl TTL TTL of record in seconds.
-d DELETE, --delete DELETE
Delete an existing record
-u UPDATE_RECORD, --update UPDATE_RECORD
Perform a DNS update on an existing record.
-U USER, --user USER The username to connect to the dyn api. Can also be
set as DYN_USER in environment.
-P PASSWORD, --password PASSWORD
The password to use with the dyn api. Can also be set
as DYN_PW in environment.
-A ACCOUNT, --account ACCOUNT
The account name used to make API requests. Can be set
as DYN_ACCOUNT in environment.
-Z ZONE, --zone ZONE The zone to take action on. Eg example.com. Can be set
as DYN_ZONE in environment.
-l, --list List all dns records as a csv file.
--verbose Print out api responses.
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Dyn is a nice DNS service. It's an alternative to Amazon's Route 53. Though I do not believe that dyn's API is as robust as amazon, with the right set of tools is just dandy.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
This tool allows for the manipulation of DNS records via the restful API.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
It currently supports the following:</div>
<ul class="task-list" style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px; margin-top: 0px; padding: 0px 0px 0px 2em;">
<li style="box-sizing: border-box;">Create A and CNAME records</li>
<li style="box-sizing: border-box;">Update A and CNAME records</li>
<li style="box-sizing: border-box;">Delete A and CNAME records</li>
<li style="box-sizing: border-box;">List all of the records as a CSV</li>
</ul>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/dyncli#requirements" name="user-content-requirements" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Requirements</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
The requests & argparse packages are required but not currently part of the standard library. Get them with pip:</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">pip install -r requirements.txt
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
You can pass your username and password directly into the script, but it's better if you setup a few environment variables. dyncli will take advantage of the following environment variables if they are present:</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">DYN_USER
DYN_PW
DYN_ZONE
DYN_ACCOUNT
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
You can activate these by appending them to your <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">~/.bash_profile</code>:</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">export DYN_USER='foo'
export DYN_PW='bar'
export DYN_ZONE='example.com'
export DYN_ACCOUNT='example'
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/dyncli#creating-a-record" name="user-content-creating-a-record" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Creating a record</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Right now both A and CNAME record creation is supported. Create a record uses the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">-c</code> flag along with the optional <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">--cname</code> flag if that's your desired record type.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
The default record type is an address (A) record.</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;"># Create an A record with default TTL
$ ./dyncli -c myfqdn.example.net -v 10.0.0.100
# Create an A record with custom TTL
$ ./dyncli -c myfqdn.example.net -v 10.0.0.100 --ttl 3600
# Create a CNAME record
$ ./dyncli -c myfqdn.example.net -v otherfqdn.example.net --cname
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/dyncli#updating-a-record" name="user-content-updating-a-record" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Updating a record</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Once records are created, they can be easily updated with the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">-u</code> or <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">--update</code> flag.</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;"># Update the TTL of an existing record
$ ./dyncli -u myfqdn.example.net --ttl 3600
# Update the value of an existing cname record
$ ./dyncli -u myfqdn.example.net -v someotherfqdn.example.net
</code></pre>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/dyncli#deleting-a-record" name="user-content-deleting-a-record" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Deleting a record</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Records are deleted by passing the <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">-d</code> or <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">--delete</code> flag.</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;"># Delete an address (A) record
$ ./dyncli -d myfqdn.example.net
# Delete a cname record (requires the --cname flag)
$ ./dyncli -d myfqdn.example.net --cname
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/dyncli#list-all-records-csv-format" name="user-content-list-all-records-csv-format" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>List all records (csv format)</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Sometimes it's useful to list all of the records. We use this to do a simple nightly backup of our DNS zone.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
The output format is a simple CSV file. Beware that if you have commas in your TXT record, they'll be translated to a pipe (<code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">|</code>).</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">$ ./dyncli --list
zone,ttl,fqdn,record_type,data
example.net,300,test.example.net,CNAME,test2.example.net
example.net,300,foo.example.net,A,172,16.0.100
example.net,3600,example.net,TXT,public_key=sdjflksdj
..
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Sometimes it's also useful to check if a zone exists before you go creating one willy nilly</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">$ ./dyncli --list | grep database
example.net,300,database.example.net,A,172.16.0.100
example.net,300,database.internal.example.net,A,172.16.0.100
example.net,300,database.something.example.net,A,172.16.0.100
(See what happens when you go on creating records without checking first?)
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px;">
If you notice any bugs please open an issue.</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-70293557647374063542014-09-15T09:22:00.002-07:002014-09-15T09:35:24.256-07:00Disposable minecraft servers in a flash with Vagrant<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://camo.githubusercontent.com/ef82ab1806808804498c0d638b92af1708c01707/68747470733a2f2f692e696d6775722e636f6d2f67366d466e74612e706e673f31" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #4183c4; margin-left: 1em; margin-right: 1em; text-decoration: none;" target="_blank"><img alt="Minecraft Vagrant" data-canonical-src="https://i.imgur.com/g6mFnta.png?1" src="https://camo.githubusercontent.com/ef82ab1806808804498c0d638b92af1708c01707/68747470733a2f2f692e696d6775722e636f6d2f67366d466e74612e706e673f31" style="border: 0px; box-sizing: border-box; max-width: 100%;" title="Minecraft running inside Vagrant" /></a></div>
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
</h1>
<div style="text-align: center;">
<span style="font-family: Arial, Helvetica, sans-serif; font-size: x-large;"><a href="https://github.com/stephen-mw/vagrant_minecraft">clone the repo</a></span></div>
<div>
<br /></div>
<h1 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 2.25em; line-height: 1.2; margin-bottom: 16px; margin-left: 0px; margin-right: 0px; margin-top: 0px !important; padding-bottom: 0.3em; position: relative;">
Disposable Minecraft Servers</h1>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Minecraft is a game where you run around punching blocks and building stuff with your imagination, basically like legos for boys and girls born in the 21st century.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Vagrant is a virtualization service for creating disposable dev environments. Now the two of them are together for running easy, shareable minecraft servers.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/vagrant_minecraft_auto_launch#what-does-this-do" name="user-content-what-does-this-do" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>What does this do</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
This is a hands-off, automated minecraft server builder. You can clone this repo on any machine that has vagrant installed to have a minecraft server up and running in minutes.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
You can run <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">vagrant up</code> on your windows, linux, or mac machine and have a minecraft server running in a compartmentalized virtual server. When you run <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">vagrant destroy</code> the virtual machine is destroyed but your persistent data is kept in <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">persistent_data</code>.</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/vagrant_minecraft_auto_launch#why" name="user-content-why" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Why</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Initially I created this vagrant config so I could quickly and easily test mods. Just start the vagrant instance and do whatever you want. If you break something or decide you don't want to use that mod any longer, simply destroy the image and the persistent data and start it again. It will be just like new.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Backing up and restoring your minecraft server is very easy, since all of your data -- including the information necessary for running the server -- is contained in just a few files and folders. You can even copy the entire directory over to a new server and run it there.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Lastly, I bet there are parents out there who want to run minecraft servers for their children. This let's you do this easily from just about any platform without having to configure anything.</div>
<h2 style="border-bottom-color: rgb(238, 238, 238); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.225; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/vagrant_minecraft_auto_launch#running-the-server" name="user-content-running-the-server" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Running the server</h2>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
First install Vagrant if you haven't already done that.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Next clone the repo:</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">git clone git@github.com:stephen-mw/vagrant_minecraft_auto_launch.git
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Pop into the vagrant server and run <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">vagrant up</code></div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">cd vagrant_minecraft_auto_launch
vagrant up
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
The server will bootstrap and install everything it needs to run minecraft. It will also start the service automatically for you.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
After the initial bootstrap you can run <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">vagrant ssh</code> to go into the server. You'll be greated with a MOTD with some helpful information:</div>
<pre style="background-color: #f7f7f7; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: 1.45; margin-bottom: 16px; overflow: auto; padding: 16px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: inherit; margin: 0px; padding: 0px; word-break: normal; word-wrap: normal;">WELCOME TO MINECRAFT!
To stop, start, restart or check the status of the the minecraft server
process, simply run:
$ service minecraft <stop|start|restart|status>
The runtime logs are available at /opt/minecraft/logs
To change the min or max server memory values, make the change in:
/etc/init/minecraft.conf
And then restart the server proces.
Status of minecraft server:
minecraft start/running, process 2344
Have fun!
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephen-mw/vagrant_minecraft_auto_launch#under-the-hood" name="user-content-under-the-hood" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Under the hood</h3>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
The server will launch an Ubuntu 12.04 image that will download and install everything you need to run minecraft automatically. It will also start the service and take care of logs. Everything related to your server will be in <code style="background-color: rgba(0, 0, 0, 0.0392157); border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13.63636302948px; line-height: normal; margin: 0px; padding: 0.2em 0px;">persistent_data</code> and that folder will survive the destruction and creation of these vagrant instances.</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
After the installation completes, you and others will be able to connect to your server at your <em style="box-sizing: border-box;">host's</em> ip address. That means if you launch the vagrant instance on a laptop that has the ip address of 192.168.0.101, then you can connect to the server at the same address (regardless of what your guest ip address is).</div>
<div style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16.3636360168457px; line-height: 23.2727279663086px;">
The instance itself doesn't need to be destroyed between runs. You can also halt it. Either way, when you bring it back online it should be running the server.<br />
<h3 style="box-sizing: border-box; font-size: 1.5em; line-height: 1.43; margin-bottom: 16px; margin-top: 1em; position: relative;">
How to get it</h3>
<div style="box-sizing: border-box; font-size: 16.3636360168457px; line-height: 23.2727279663086px; margin-bottom: 16px;">
Clone the repo: <a href="https://github.com/stephen-mw/vagrant_minecraft">https://github.com/stephen-mw/vagrant_minecraft</a></div>
</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com1tag:blogger.com,1999:blog-2870713865752955687.post-14008311308812083582014-09-14T17:03:00.003-07:002014-09-14T17:03:44.412-07:00Minecraft server upstart script<div dir="ltr" style="text-align: left;" trbidi="on">
I see a lot of people running minecraft server in strange ways: nohup, bg & disown, tmux, screen, etc. The problem with those options is that they are all ephemeral. If you restart your server you'll need to do it all over again.<br />
<br />
Here's a simple upstart script that starts and watches your minecraft server. It runs as a service and works for centos 6.5+ and ubuntu 12.04+<br />
<br />
Once you create the file at <span style="font-family: Courier New, Courier, monospace;">/etc/init/minecraft.conf</span>, simply run:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">initctl reload-configuration</span><br />
<span style="font-family: Courier New, Courier, monospace;">service minecraft <start|stop|status></span><br />
<br />
upstart script:<span style="background-color: white; font-family: Courier New, Courier, monospace;"><br /></span>
<span style="background-color: white; font-family: Courier New, Courier, monospace;"># Minecraft upstart script</span><br />
<span style="background-color: white; font-family: Courier New, Courier, monospace;"><br /></span>
<span style="background-color: white; font-family: Courier New, Courier, monospace;">start on (local-filesystems and net-device-up IFACE!=lo)</span><br />
<span style="background-color: white; font-family: Courier New, Courier, monospace;">stop on [!12345]</span><br />
<span style="background-color: white; font-family: Courier New, Courier, monospace;"><br /></span>
<span style="background-color: white; font-family: Courier New, Courier, monospace;">respawn</span><br />
<span style="background-color: white; font-family: Courier New, Courier, monospace;"><br /></span>
<span style="background-color: white; font-family: Courier New, Courier, monospace;">chdir SOME_MINECRAFT_DIRECTORY</span><br />
<span style="background-color: white; font-family: Courier New, Courier, monospace;"><br /></span>
<span style="background-color: white; font-family: Courier New, Courier, monospace;">exec java -Xmx1024M -Xms1024M -jar minecraft_server.1.8.jar nogui</span><br />
<span style="background-color: white; font-family: Courier New, Courier, monospace;"><br /></span>
Logs for the server will be rotated by the server and are available at <span style="background-color: white; font-family: Courier New, Courier, monospace;">/var/log/upstart/minecraft.log</span></div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com3tag:blogger.com,1999:blog-2870713865752955687.post-88205024617034633662014-07-28T22:00:00.001-07:002014-07-28T22:00:33.098-07:00ec2list -- quickly and easily list ec2 instances across all accounts and regions<div dir="ltr" style="text-align: left;" trbidi="on">
Here's a quick tool I cooked up after working in with multiple AWS accounts in many regions. Sometimes I just need a particular piece of information about a host and I only had its instance id. Before this script I would have to run multiple aws calls in different regions until I found the instance.<br />
<br />
The script itself is a wrapper around the aws cli tools. It will gather a list of instances in all accounts you specify and in all of the regions. It's multithreaded and I find it finishes in about 4 to 5 seconds. You'll get better performance if you comment out regions that you're not using.<br />
<br />
Just <a href="https://github.com/stephendotexe/ec2list">clone the repo</a> and execute.<br />
<h1 style="border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
Usage</h1>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">usage: ec2list [-h] [-i INSTANCES] [-v] [-a] [-f FILTER]
optional arguments:
-h, --help show this help message and exit
-i INSTANCES, --instances INSTANCES
Comma-separated list of instances to filter results.
-v, --verbose Print all host metadata.
-a, --all List all hosts, even those that aren't running.
-f FILTER, --filter FILTER
key value filters to pass directly to command. Eg:
Name=instance-type,Value=m1.small
</code></pre>
<h1 style="border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-bottom-width: 1px; box-sizing: border-box; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 2.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephendotexe/ec2list#prerequisites" name="user-content-prerequisites" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Prerequisites</h1>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
You must have a $HOME/.aws/config file setup with the proper credentials.</div>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
An example profile:</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">[profile production]
aws_access_key_id=AKIAFOO
aws_secret_access_key=grzOgbar
region=us-west-1
[profile staging]
aws_access_key_id=AKIAIFOO
aws_secret_access_key=BAYS232bar
region=us-west-1
</code></pre>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
You can test that the different profiles are active by running the aws cli tool</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">aws ec2 describe-instances --profile=production
aws ec2 describe-instances --profile=staging
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephendotexe/ec2list#listing-all-instances-in-a-succinct-manner" name="user-content-listing-all-instances-in-a-succinct-manner" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Listing all instances in a succinct manner.</h3>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
The columns when run this way will always be predictable (unlike -v). Useful if you're using awk or other things.</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">$ ./list
i-7e15d971 stephen_test_001 10.0.0.100 54.183.84.15 m3.large production
i-7e15d971 stephen_test_002 10.0.0.100 54.183.84.16 m3.large staging
...
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephendotexe/ec2list#list-instances-that-are-also-stopped" name="user-content-list-instances-that-are-also-stopped" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>List instances that are also stopped</h3>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
By default only running instances will be shown. Use the -a or --all flag to show all instances, even those that are stopped.</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">$ ./list -a
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephendotexe/ec2list#be-verbose-prints-all-available-instance-info" name="user-content-be-verbose-prints-all-available-instance-info" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Be verbose </h3>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
Verbose prints everything returned by ec2. The return values are unordered.</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">./list -v
i-7e15d971:
Monitoring: {"State": "disabled"}
PublicDnsName: ec2-54-131-88-95.us-west-2.compute.amazonaws.com
RootDeviceType: ebs
State: {"Code": 16, "Name": "running"}
EbsOptimized: False
...
i-bba5d6e6:
Monitoring: {"State": "disabled"}
PublicDnsName: ec2-54-210-162-78.us-west-1.compute.amazonaws.com
RootDeviceType: ebs
State: {"Code": 16, "Name": "running"}
EbsOptimized: False
...
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephendotexe/ec2list#print-only-information-for-a-select-number-of-instances" name="user-content-print-only-information-for-a-select-number-of-instances" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Filter by a list of instance IDs</h3>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
To easily filter instances by instance id, they can be passed as a comma-separated list with the <code style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; margin: 0px; padding: 0px;">-i</code> or <code style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; margin: 0px; padding: 0px;">--instances</code> flag.</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">./list -i i-bba5d6e6,i-cad1b0c2,i-afa406f2
</code></pre>
<h3 style="box-sizing: border-box; color: #333333; cursor: text; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 1.5em; line-height: 1.7; margin: 1em 0px 15px; padding: 0px; position: relative;">
<a aria-hidden="true" class="anchor" href="https://github.com/stephendotexe/ec2list#print-only-instances-that-are-an-m1small" name="user-content-print-only-instances-that-are-an-m1small" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; bottom: 0px; box-sizing: border-box; color: #4183c4; cursor: pointer; display: block; left: 0px; margin-left: -30px; padding-left: 30px; padding-right: 6px; position: absolute; text-decoration: none; top: 0px;"></a>Print only instances that are an m1.small, or other things</h3>
<div style="box-sizing: border-box; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 15.454545021057129px; line-height: 23.18181800842285px; margin-bottom: 15px; margin-top: 15px;">
Note that the filters arg allows you to pass filters down directory to the underlying aws ec2 command. See the <a href="http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; box-sizing: border-box; color: #4183c4; text-decoration: none;">ec2 api</a> for information on the types of filtering you can do.</div>
<pre style="background-color: #f8f8f8; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid rgb(221, 221, 221); box-sizing: border-box; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 13px; line-height: 19px; margin-top: 15px; overflow: auto; padding: 6px 10px; word-wrap: normal;"><code style="background: transparent; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: none; box-sizing: border-box; display: inline; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 12px; line-height: inherit; margin: 0px; padding: 0px; word-wrap: normal;">$ ./list -f Name=instance-type,Values=m1.small</code></pre>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-3426589193119873582014-05-08T09:33:00.002-07:002020-12-01T16:49:38.189-08:00Converting NMEA latitude and longitude coordinates to degrees decimal for use in google maps<div dir="ltr" style="text-align: left;" trbidi="on">
I've been tinkering around with my GlobalSat bu-353 USB gps receiver lately. Initially I was confused about the coordinates I received from the device. I mapped them in google maps and it showed my location in the middle of the pacific ocean. Do I really live in the plastic bag vortex in the pacific??<br />
<br />
After some googling I realized I wasn't using the correct formula to convert the lat/long <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA</a>-specified format to <a href="http://en.wikipedia.org/wiki/Decimal_degrees">decimal degrees</a> acceptable to google maps.<br />
<br />
According to the <a href="http://www.usglobalsat.com/store/downloads/NMEA_commands.pdf">specs</a>, NMEA specifies latitude as ddmm.mmmm and longitude as dddmm.mmmm. To convert these to decimal degrees, we need to simply divide the minute (mm.mmmm) by 60.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">(d)dd + (mm.mmmm / 60)</span><br />
<br />
The first "d" is optional and only pertains to longitudinal coordinates.<br />
<br />
Plotting these coordinates in google maps is easy. Just use the following URL:<br />
<br />
http://maps.google.com/maps?q=<latitude>,<longitude></div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com1tag:blogger.com,1999:blog-2870713865752955687.post-3475577994127093422014-02-14T12:12:00.002-08:002014-03-20T00:07:21.652-07:00Move over upstart and make way for systemd<div dir="ltr" style="text-align: left;" trbidi="on">
Earlier this week the Debian technical committee voted to make systemd the default init system for Debian. It was a nail-biter to follow, and it essentially came down to a <a href="https://lists.debian.org/debian-ctte/2014/02/msg00405.html">tie-breaker vote</a> cast by Bdale Garbee.<br />
<br />
The result is clear: systemd will be the default init system for Debian -- and also Ubuntu -- going forward.<br />
<br />
Mark Shuttleworth of Canonical confirmed Ubuntu's decision to follow suit in a blog post called "<a href="http://www.markshuttleworth.com/archives/1316">Losing Graciously</a>". No drama, no attempt to revote or repeal the vote.<br />
<br />
If only politics worked that smoothly.<br />
<br />
Now it's time to familiarize yourself with <a href="https://wiki.debian.org/systemd">systemd</a>. I recommend you start writing all future init scripts in systemd.<br />
<br />
The time frame for obsolescence of upstart and sysVinit is unclear for Ubuntu, but I predict around 7 years, so you have time to migrate.<br />
<br />
Here's how I got that number (remember that odd number of releases are 2 year support):<br />
<br />
13.04 is already out and obviously not part of the decision<br />
14.04 is too far into the development stages<br />
15.04 nobody will use because it's not "true" LTS<br />
16.04: the only logical next release to enforce this decision.<br />
<br />
I'll be writing more about systemd in the future. First I'm going to begin my own conversation from upstart so I can figure out how to use the dang thing. I'm glad that now I can write a service that will work across multiple distros.</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-78384530542367206842014-01-25T12:07:00.003-08:002014-02-27T11:57:49.554-08:00Zabbix Server 2.2 with Percona 5.6 Auto Install on Ubuntu<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/9/99/Zabbix.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/9/99/Zabbix.png" height="230" width="320" /></a></div>
<br />
<br />
Here's an easy-install for Zabbix server 2.2 running on Percona 5.6.<br />
<br />
<div style="text-align: center;">
<span style="font-size: large;"><a href="https://github.com/stephendotexe/zabbix_server_2.2_and_percona_easy_install">Go here to clone the repo</a></span></div>
<br />
Zabbix is an enterprise monitoring tool. I've been using it for about two years and find it decent, though it does have shortfalls (especially when dealing with aggregate metrics). If you're dealing with less than two or three hundred hosts, then I think Zabbix is a great tool.<br />
<br />
Percona is a high performance mysql fork. This auto-install will download the Zabbix source code and compile it. This is the easiest way I can find to installing Zabbix server without using legacy mysql software.<br />
<br />
If you're looking for high-performance metric aggregation, then may I suggest the venerable <a href="http://opentsdb.net/">OpenTSDB</a> or the tried-and-true <a href="http://graphite.wikidot.com/">graphite</a>? These tools can be easily integrated with Zabbix via their respective APIs.<br />
<br />
<div style="text-align: left;">
<span style="font-family: inherit; font-size: x-large;">How to install</span></div>
<br />
Simply clone the repo and run:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">./bootstrap</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-size: x-large;">Requirements</span><br />
<div>
<br />
There are a few things that are assumed. The first is that you don't have apache running or installed. If you do then beware this will nuke your default site vhost and overwrite it with a Zabbix specific one. It also assumes you don't have mysql installed.</div>
<div>
<br /></div>
<div>
As always you should inspect the code before running it on your system. Enjoy and let me know if you have any issues.</div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-71819447044764210222014-01-22T16:57:00.002-08:002014-02-13T09:31:39.589-08:00UDP only rsyslog server and client on Ubuntu<div dir="ltr" style="text-align: left;" trbidi="on">
The first thing you'll need to do is install a new version of rsyslog. There's a <a href="https://bugs.launchpad.net/ubuntu/+source/rsyslog/+bug/789174">bug</a> in the version that comes along with Ubuntu 12.04 that prevents rsyslog from listening on a privileged port if you're using drop-privileges.
You can read instructions for installing a newer version of rsyslog <a href="http://www.rsyslog.com/ubuntu-repository/">here</a>.
Once you've done that, open up <span style="font-family: Courier New, Courier, monospace;">/etc/rsyslog.conf</span> and uncomment the following lines:<br />
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#$ModLoad imudp</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#$UDPServerRun 514</span><br />
<br />
Restart rsyslog and you're done on the server. Now head over to a client and open up <span style="font-family: Courier New, Courier, monospace;">/etc/rsyslog.d/50-default.conf</span> and make the following addition to the top of the file:<br />
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">*.* @your_server:514</span><br />
<br />
Note that the single @ sign is what designates the sending to UDP only. Restart rsyslog on the server and you can test to see if logs are being sent using the logger command:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">logger -t TEST testing</span></div>
</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com1tag:blogger.com,1999:blog-2870713865752955687.post-75660753835024638742013-11-20T16:45:00.000-08:002013-11-20T16:45:11.866-08:00Easily convert hex to ints and vice versa with python and the command line<div dir="ltr" style="text-align: left;" trbidi="on">
I've started a lot of work lately with the <a href="https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CFUQFjAA&url=http%3A%2F%2Fwww.adafruit.com%2Fdatasheets%2FSSD1306.pdf&ei=D1eNUtDuFKmqiQL6ooEQ&usg=AFQjCNEWYJ8tsdP35_0uLGjZ9ZALs0HfpA&sig2=JDLE6BwB1IlGB_n7353p2w&bvm=bv.56987063,d.cGE">ssd1306 oled display</a> (which you can pick up for a few bucks on ebay) and my raspbery pi. While sending commands I've found it useful to be able to easily convert between ints and hexadecimal strings and back again.<br />
<br />
To convert a hexadecimal value to an int on the command line:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">python -c 'print int(0x7f)'</span><br />
<span style="font-family: Courier New, Courier, monospace;">127</span><br />
<br />
And back again:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">python -c 'print hex(127)</span><br />
<span style="font-family: Courier New, Courier, monospace;">0x7f</span><br />
<br />
For floats you can use the float.hex method:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">python -c 'print float.hex(120.5)'</span><br />
<span style="font-family: Courier New, Courier, monospace;">0x1.e200000000000p+6</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
Maybe you want that trimmed:<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">python -c 'print float.hex(120.5)[:7]'</span><br />
<span style="font-family: Courier New, Courier, monospace;"></span><br />
<span style="font-family: Courier New, Courier, monospace;">0x1.e20</span><br />
<br />
It's worth noting that the '-c' flag being passed to python essentially tells python that the first argument is a script it should execute normally.</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0tag:blogger.com,1999:blog-2870713865752955687.post-63416526404225648542013-11-18T00:57:00.001-08:002013-11-18T10:08:44.687-08:00Verifying JSON easily on the command line<div dir="ltr" style="text-align: left;" trbidi="on">
You can pipe stdout into <span style="font-family: Courier New, Courier, monospace;">python -mjson.tool</span> to validate it. It makes for quick and easy json validation on the command line.<br />
<br />
We'll create a simple json file:<br />
<span style="background-color: white;"><br /></span>
<span style="background-color: white; color: #444444; font-family: Courier New, Courier, monospace;">> somefile.txt</span><br />
<span style="background-color: white; color: #444444; font-family: Courier New, Courier, monospace;">{"someval": "something", "anotherval": 3}</span><br />
<br />
Now pipe this into json.tools and check the output.<br />
<br />
<span style="color: #444444; font-family: Courier New, Courier, monospace;">$ cat somefile.txt | python -mjson.tool</span><br />
<span style="color: #444444; font-family: Courier New, Courier, monospace;">{</span><br />
<span style="color: #444444; font-family: Courier New, Courier, monospace;"> "anotherval": 3,</span><br />
<span style="color: #444444; font-family: Courier New, Courier, monospace;"> "someval": "something"</span><br />
<span style="color: #444444; font-family: Courier New, Courier, monospace;">}</span><br />
<br />
Cool. It even formatted it nicely for us. Let's break it and see what happens.<br />
<br />
Single quotes are not valid according <a href="http://www.ietf.org/rfc/rfc4627.txt">rfc4627</a>.<br />
<br />
<span style="color: #444444; font-family: Courier New, Courier, monospace;">> somefile.txt</span><br />
<span style="background-color: white; color: #444444; font-family: 'Courier New', Courier, monospace;">{'someval': 'something', 'anotherval': 3}</span><br />
<span style="background-color: white; color: #444444; font-family: 'Courier New', Courier, monospace;"><br /></span>
<span style="color: #444444; font-family: Courier New, Courier, monospace;">$ cat somefile.txt | python -mjson.tool</span><br />
<span style="color: #444444; font-family: Courier New, Courier, monospace;">Expecting property name: line 1 column 2 (char 1)</span><br />
<br />
Not the most useful traceback, but at least you know it's not valid.</div>
Stephen Woodhttp://www.blogger.com/profile/04334788719882624757noreply@blogger.com0