diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..6bd68921 --- /dev/null +++ b/404.html @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + Terrabutler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..67e9da56 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +docs.montblu.eu diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 00000000..8ff03620 Binary files /dev/null and b/assets/favicon.ico differ diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 00000000..1cf13b9f Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.51d95adb.min.js b/assets/javascripts/bundle.51d95adb.min.js new file mode 100644 index 00000000..b20ec683 --- /dev/null +++ b/assets/javascripts/bundle.51d95adb.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Hi=Object.create;var xr=Object.defineProperty;var Pi=Object.getOwnPropertyDescriptor;var $i=Object.getOwnPropertyNames,kt=Object.getOwnPropertySymbols,Ii=Object.getPrototypeOf,Er=Object.prototype.hasOwnProperty,an=Object.prototype.propertyIsEnumerable;var on=(e,t,r)=>t in e?xr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))Er.call(t,r)&&on(e,r,t[r]);if(kt)for(var r of kt(t))an.call(t,r)&&on(e,r,t[r]);return e};var sn=(e,t)=>{var r={};for(var n in e)Er.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&kt)for(var n of kt(e))t.indexOf(n)<0&&an.call(e,n)&&(r[n]=e[n]);return r};var Ht=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Fi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $i(t))!Er.call(e,o)&&o!==r&&xr(e,o,{get:()=>t[o],enumerable:!(n=Pi(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Hi(Ii(e)):{},Fi(t||!e||!e.__esModule?xr(r,"default",{value:e,enumerable:!0}):r,e));var fn=Ht((wr,cn)=>{(function(e,t){typeof wr=="object"&&typeof cn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(wr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(T){return!!(T&&T!==document&&T.nodeName!=="HTML"&&T.nodeName!=="BODY"&&"classList"in T&&"contains"in T.classList)}function f(T){var Ke=T.type,We=T.tagName;return!!(We==="INPUT"&&a[Ke]&&!T.readOnly||We==="TEXTAREA"&&!T.readOnly||T.isContentEditable)}function c(T){T.classList.contains("focus-visible")||(T.classList.add("focus-visible"),T.setAttribute("data-focus-visible-added",""))}function u(T){T.hasAttribute("data-focus-visible-added")&&(T.classList.remove("focus-visible"),T.removeAttribute("data-focus-visible-added"))}function p(T){T.metaKey||T.altKey||T.ctrlKey||(s(r.activeElement)&&c(r.activeElement),n=!0)}function m(T){n=!1}function d(T){s(T.target)&&(n||f(T.target))&&c(T.target)}function h(T){s(T.target)&&(T.target.classList.contains("focus-visible")||T.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(T.target))}function v(T){document.visibilityState==="hidden"&&(o&&(n=!0),B())}function B(){document.addEventListener("mousemove",z),document.addEventListener("mousedown",z),document.addEventListener("mouseup",z),document.addEventListener("pointermove",z),document.addEventListener("pointerdown",z),document.addEventListener("pointerup",z),document.addEventListener("touchmove",z),document.addEventListener("touchstart",z),document.addEventListener("touchend",z)}function re(){document.removeEventListener("mousemove",z),document.removeEventListener("mousedown",z),document.removeEventListener("mouseup",z),document.removeEventListener("pointermove",z),document.removeEventListener("pointerdown",z),document.removeEventListener("pointerup",z),document.removeEventListener("touchmove",z),document.removeEventListener("touchstart",z),document.removeEventListener("touchend",z)}function z(T){T.target.nodeName&&T.target.nodeName.toLowerCase()==="html"||(n=!1,re())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),B(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var un=Ht(Sr=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},a=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(re,z){d.append(z,re)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(T){throw new Error("URL unable to set base "+c+" due to "+T)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,B=!0,re=this;["append","delete","set"].forEach(function(T){var Ke=h[T];h[T]=function(){Ke.apply(h,arguments),v&&(B=!1,re.search=h.toString(),B=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var z=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==z&&(z=this.search,B&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},a=i.prototype,s=function(f){Object.defineProperty(a,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){s(f)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr)});var Qr=Ht((Lt,Kr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Lt=="object"&&typeof Kr=="object"?Kr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Lt=="object"?Lt.ClipboardJS=r():t.ClipboardJS=r()})(Lt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return ki}});var a=i(279),s=i.n(a),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(O){return!1}}var d=function(O){var w=p()(O);return m("cut"),w},h=d;function v(j){var O=document.documentElement.getAttribute("dir")==="rtl",w=document.createElement("textarea");w.style.fontSize="12pt",w.style.border="0",w.style.padding="0",w.style.margin="0",w.style.position="absolute",w.style[O?"right":"left"]="-9999px";var k=window.pageYOffset||document.documentElement.scrollTop;return w.style.top="".concat(k,"px"),w.setAttribute("readonly",""),w.value=j,w}var B=function(O,w){var k=v(O);w.container.appendChild(k);var F=p()(k);return m("copy"),k.remove(),F},re=function(O){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},k="";return typeof O=="string"?k=B(O,w):O instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(O==null?void 0:O.type)?k=B(O.value,w):(k=p()(O),m("copy")),k},z=re;function T(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?T=function(w){return typeof w}:T=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},T(j)}var Ke=function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},w=O.action,k=w===void 0?"copy":w,F=O.container,q=O.target,Le=O.text;if(k!=="copy"&&k!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&T(q)==="object"&&q.nodeType===1){if(k==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(k==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Le)return z(Le,{container:F});if(q)return k==="cut"?h(q):z(q,{container:F})},We=Ke;function Ie(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Ie=function(w){return typeof w}:Ie=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},Ie(j)}function Ti(j,O){if(!(j instanceof O))throw new TypeError("Cannot call a class as a function")}function nn(j,O){for(var w=0;w0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof F.action=="function"?F.action:this.defaultAction,this.target=typeof F.target=="function"?F.target:this.defaultTarget,this.text=typeof F.text=="function"?F.text:this.defaultText,this.container=Ie(F.container)==="object"?F.container:document.body}},{key:"listenClick",value:function(F){var q=this;this.listener=c()(F,"click",function(Le){return q.onClick(Le)})}},{key:"onClick",value:function(F){var q=F.delegateTarget||F.currentTarget,Le=this.action(q)||"copy",Rt=We({action:Le,container:this.container,target:this.target(q),text:this.text(q)});this.emit(Rt?"success":"error",{action:Le,text:Rt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(F){return yr("action",F)}},{key:"defaultTarget",value:function(F){var q=yr("target",F);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(F){return yr("text",F)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(F){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return z(F,q)}},{key:"cut",value:function(F){return h(F)}},{key:"isSupported",value:function(){var F=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof F=="string"?[F]:F,Le=!!document.queryCommandSupported;return q.forEach(function(Rt){Le=Le&&!!document.queryCommandSupported(Rt)}),Le}}]),w}(s()),ki=Ri},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,f){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(f))return s;s=s.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function s(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?s.apply(null,arguments):typeof m=="function"?s.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return s(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),s=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(m))return c(m,d,h);if(a.nodeList(m))return u(m,d,h);if(a.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return s(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),a=f.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,s){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var f=this;function c(){f.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=s.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var is=/["'&<>]/;Jo.exports=as;function as(e){var t=""+e,r=is.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],a;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(s){a={error:s}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(a)throw a.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||s(m,d)})})}function s(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof Xe?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){s("next",m)}function u(m){s("throw",m)}function p(m,d){m(d),i.shift(),i.length&&s(i[0][0],i[0][1])}}function mn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof xe=="function"?xe(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(a){return new Promise(function(s,f){a=e[i](a),o(s,f,a.done,a.value)})}}function o(i,a,s,f){Promise.resolve(f).then(function(c){i({value:c,done:s})},a)}}function A(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var $t=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function De(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Fe=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=xe(a),f=s.next();!f.done;f=s.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var u=this.initialTeardown;if(A(u))try{u()}catch(v){i=v instanceof $t?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=xe(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{dn(h)}catch(v){i=i!=null?i:[],v instanceof $t?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new $t(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)dn(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&De(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&De(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Or=Fe.EMPTY;function It(e){return e instanceof Fe||e&&"closed"in e&&A(e.remove)&&A(e.add)&&A(e.unsubscribe)}function dn(e){A(e)?e():e.unsubscribe()}var Ae={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?Or:(this.currentObservers=null,s.push(r),new Fe(function(){n.currentObservers=null,De(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new wn(r,n)},t}(U);var wn=function(e){ne(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Or},t}(E);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ne(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,f=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Ut);var On=function(e){ne(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var we=new On(Tn);var R=new U(function(e){return e.complete()});function Dt(e){return e&&A(e.schedule)}function kr(e){return e[e.length-1]}function Qe(e){return A(kr(e))?e.pop():void 0}function Se(e){return Dt(kr(e))?e.pop():void 0}function Vt(e,t){return typeof kr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function zt(e){return A(e==null?void 0:e.then)}function Nt(e){return A(e[ft])}function qt(e){return Symbol.asyncIterator&&A(e==null?void 0:e[Symbol.asyncIterator])}function Kt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ki(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=Ki();function Yt(e){return A(e==null?void 0:e[Qt])}function Gt(e){return ln(this,arguments,function(){var r,n,o,i;return Pt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,Xe(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,Xe(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,Xe(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Bt(e){return A(e==null?void 0:e.getReader)}function $(e){if(e instanceof U)return e;if(e!=null){if(Nt(e))return Qi(e);if(pt(e))return Yi(e);if(zt(e))return Gi(e);if(qt(e))return _n(e);if(Yt(e))return Bi(e);if(Bt(e))return Ji(e)}throw Kt(e)}function Qi(e){return new U(function(t){var r=e[ft]();if(A(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Yi(e){return new U(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?_(function(o,i){return e(o,i,n)}):me,Oe(1),r?He(t):zn(function(){return new Xt}))}}function Nn(){for(var e=[],t=0;t=2,!0))}function fe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new E}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,f=s===void 0?!0:s;return function(c){var u,p,m,d=0,h=!1,v=!1,B=function(){p==null||p.unsubscribe(),p=void 0},re=function(){B(),u=m=void 0,h=v=!1},z=function(){var T=u;re(),T==null||T.unsubscribe()};return g(function(T,Ke){d++,!v&&!h&&B();var We=m=m!=null?m:r();Ke.add(function(){d--,d===0&&!v&&!h&&(p=jr(z,f))}),We.subscribe(Ke),!u&&d>0&&(u=new et({next:function(Ie){return We.next(Ie)},error:function(Ie){v=!0,B(),p=jr(re,o,Ie),We.error(Ie)},complete:function(){h=!0,B(),p=jr(re,a),We.complete()}}),$(T).subscribe(u))})(c)}}function jr(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function V(e,t=document){let r=se(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function se(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),N(e===_e()),Y())}function Be(e){return{x:e.offsetLeft,y:e.offsetTop}}function Yn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,we),l(()=>Be(e)),N(Be(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,we),l(()=>rr(e)),N(rr(e)))}var Bn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),xa?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ya.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Jn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Zn=typeof WeakMap!="undefined"?new WeakMap:new Bn,eo=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Ea.getInstance(),n=new Ra(t,r,this);Zn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){eo.prototype[e]=function(){var t;return(t=Zn.get(this))[e].apply(t,arguments)}});var ka=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:eo}(),to=ka;var ro=new E,Ha=I(()=>H(new to(e=>{for(let t of e)ro.next(t)}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){return Ha.pipe(S(t=>t.observe(e)),x(t=>ro.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(()=>de(e)))),N(de(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var no=new E,Pa=I(()=>H(new IntersectionObserver(e=>{for(let t of e)no.next(t)},{threshold:0}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function sr(e){return Pa.pipe(S(t=>t.observe(e)),x(t=>no.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function oo(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=de(e),o=bt(e);return r>=o.height-n.height-t}),Y())}var cr={drawer:V("[data-md-toggle=drawer]"),search:V("[data-md-toggle=search]")};function io(e){return cr[e].checked}function qe(e,t){cr[e].checked!==t&&cr[e].click()}function je(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),N(t.checked))}function $a(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ia(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(N(!1))}function ao(){let e=b(window,"keydown").pipe(_(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:io("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),_(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!$a(n,r)}return!0}),fe());return Ia().pipe(x(t=>t?R:e))}function Me(){return new URL(location.href)}function ot(e){location.href=e.href}function so(){return new E}function co(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)co(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)co(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function fo(){return location.hash.substring(1)}function uo(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Fa(){return b(window,"hashchange").pipe(l(fo),N(fo()),_(e=>e.length>0),J(1))}function po(){return Fa().pipe(l(e=>se(`[id="${e}"]`)),_(e=>typeof e!="undefined"))}function Nr(e){let t=matchMedia(e);return Zt(r=>t.addListener(()=>r(t.matches))).pipe(N(t.matches))}function lo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(N(e.matches))}function qr(e,t){return e.pipe(x(r=>r?t():R))}function ur(e,t={credentials:"same-origin"}){return ve(fetch(`${e}`,t)).pipe(ce(()=>R),x(r=>r.status!==200?Tt(()=>new Error(r.statusText)):H(r)))}function Ue(e,t){return ur(e,t).pipe(x(r=>r.json()),J(1))}function mo(e,t){let r=new DOMParser;return ur(e,t).pipe(x(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),J(1))}function pr(e){let t=M("script",{src:e});return I(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(x(()=>Tt(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),C(()=>document.head.removeChild(t)),Oe(1))))}function ho(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function bo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(ho),N(ho()))}function vo(){return{width:innerWidth,height:innerHeight}}function go(){return b(window,"resize",{passive:!0}).pipe(l(vo),N(vo()))}function yo(){return Q([bo(),go()]).pipe(l(([e,t])=>({offset:e,size:t})),J(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(X("size")),o=Q([n,r]).pipe(l(()=>Be(e)));return Q([r,t,o]).pipe(l(([{height:i},{offset:a,size:s},{x:f,y:c}])=>({offset:{x:a.x-f,y:a.y-c+i},size:s})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(a=>{let s=document.createElement("script");s.src=i,s.onload=a,document.body.appendChild(s)})),Promise.resolve())}var r=class{constructor(n){this.url=n,this.onerror=null,this.onmessage=null,this.onmessageerror=null,this.m=a=>{a.source===this.w&&(a.stopImmediatePropagation(),this.dispatchEvent(new MessageEvent("message",{data:a.data})),this.onmessage&&this.onmessage(a))},this.e=(a,s,f,c,u)=>{if(s===this.url.toString()){let p=new ErrorEvent("error",{message:a,filename:s,lineno:f,colno:c,error:u});this.dispatchEvent(p),this.onerror&&this.onerror(p)}};let o=new EventTarget;this.addEventListener=o.addEventListener.bind(o),this.removeEventListener=o.removeEventListener.bind(o),this.dispatchEvent=o.dispatchEvent.bind(o);let i=document.createElement("iframe");i.width=i.height=i.frameBorder="0",document.body.appendChild(this.iframe=i),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Create a new project

+

Before proceeding make sure that you have followed the Installation.

+

Configure direnv

+

For direnv to work properly it needs to be hooked into the shell. +Check direnv docs to know more: https://direnv.net/docs/hook.html

+

Make sure that you have followed direnv documentation before proceeding.

+

Configure Terrabutler

+

Create your project folder

+
mkdir <project_name>
+
+

Download Template

+

Start by downloading the Terrabutler Template Project from the repository source below:

+

Version-shield

+

Copy the files inside ./terrabutler-template/ to the root of your project folder.

+
$ cp -a /terrabutler-template/. /<project_name>/
+
+

Create a new workspace

+

Before configuring terrabutler, inside <project_name>/site_inception folder, you will need to create a Terraform Workspace: +For example, we are gonna call it "staging"

+
$ cd site_inception
+$ terraform workspace new staging
+
+

Change Variables

+

Run the script ./<project_name>/config_template.sh, with the following arguments, located inside the project folder root:

+
$ ./config_template.sh -d <domain> -e <environment_name> -p <project_name>
+
+USAGE:
+   ./config_template [FLAG] [STRING]
+
+FLAGS:
+   -o <organization_name>   The name for your organization.  
+                            Example: -o example
+
+   -d <domain>              The domain of your organization. 
+                            Example: -d example.com
+
+   -e <environment_name>    The environment name of your organization. 
+                            Example: -e staging
+
+
+Danger +

This script only works with the template folder! Don't use it in another project folders! +./terrabutler-template/config_template.sh

+
+

Terraform

+

Start by installing Terraform with tfenv:

+
$ tfenv install 
+
+

Initialize the Project

+

Perform an Terraform Initialization inside site_inception:

+

$ cd /site_inception/
+$ terraform init
+
+Perform an Terraform Apply with the .tfvars inside /config/variables/:

+

./configs/variables/global.tfvars
+./configs/variables/<project_name>-<environment_name>.tfvars"
+./configs/variables/<project_name>-<environment_name>-inception.tfvars"

+
$ terraform apply -var-file="../configs/variables/global.tfvars" -var-file="../configs/variables/<project_name>-<environment_name>.tfvars" -var-file="../configs/variables/<project_name>-<environment_name>-inception.tfvars"
+
+

Change local to remote backend

+

Uncomment the remote backend line

+

Remove the commented line as below, in the terrabutler-template in the path ./site-inception/terraform.tf to change from local to remote.

+
backend "s3" {}
+
+

Perform an Terraform initialization with the backend config file,located in /configs/backend/ to update the new changes:

+
$ terraform init -backend-config=<inception_backend_path>  
+
+
+Tip +
+

Example: + $ terraform init -backend-config="./configs/backends/--inception.tfvars"

+

Delete the local state

+

Delete the local state in /site_inception, as it is not necessary:

+
$ rm -rf terraform.tfstate.d/ terraform.tfstate terraform.tfstate.backup
+
+

Terrabutler commands

+

Terrabutler Plan

+

Perform an Terrabutler Plan to ensure everything is ok, and plan any changes:

+
$ terrabutler tf -site inception plan
+
+

Terrabutler Apply

+

Perform an Terrabutler Apply to apply the planned changes:

+
$ terrabutler tf -site inception apply
+
+

Terrabutler Destroy

+

Perform an Terrabutler Destroy to delete or undo any changes made in the provider:

+
$ terrabutler tf -site inception destroy
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..3dabf702 --- /dev/null +++ b/index.html @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Terrabutler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + +
+

Image title

+
+

Terrabutler

+

The utility that helps keeping your IaC in one piece

+

GitHub release (latest by date) +GitHub Workflow Status +GitHub +GitHub Repo stars

+
+

What is Terrabutler?

+

Terrabutler is a wrapper written in Python that helps maintaining IaC (Infrastructure as code) projects +using Terraform by managing the environments.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/installation/index.html b/installation/index.html new file mode 100644 index 00000000..f74cbe62 --- /dev/null +++ b/installation/index.html @@ -0,0 +1,559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Installation - Terrabutler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Installation

+

Before proceeding make sure that you have the requirements.

+

Download the binaries and extract them

+

All the binaries versions are available inside the releases pages

+

To download the latest binaries run the following command:

+
wget -qO- https://github.com/montblu/terrabutler/releases/download/<VERSION>/terrabutler-<OS>-<ARCH>-<VERSION>.tar.gz | tar -zxvf - terrabutler
+
+

Where <VERSION> is the version of the release.

+

For example, to download Terrabutler v0.2.0 for Linux x64, just run:

+
wget -qO- https://github.com/montblu/terrabutler/releases/download/v0.2.0/terrabutler-linux-x64-v0.2.0.tar.gz | tar -zxvf - terrabutler
+
+

Install the binaries

+

To install the binaries into your system simply run the installer script inside the terrabutler folder:

+
sudo terrabutler/install
+
+

All the binaries will be placed inside the /usr/share/terrabutler folder and the bin inside the /usr/bin folder

+
+Tip +

If you wanna set the location where terrabutler will be installed you can define it by passing arguments when running the install script. +This arguments can be seen by running:

+
terrabutler/install -h
+
+

Example of installing for local user only (no need to run the install script as sudo):

+
terrabutler/install -i ~/.local/share/terrabutler -b ~/.local/bin
+
+
+

Check if the installation was successful

+

You should be able to run:

+
terrabutler --version
+
+

and the output should be:

+
Terrabutler: v0.2.0
+
+

If the output is not similar to the one above, then something went wrong during the installation.

+

How to update to a newer version?

+

If you have Terrabutler already installed and want to update to a newer version just do all the installation process again. +When you will be running the installer script it should prompt if you want to upgrade the Terrabutler, as we can see below:

+
Found preexisting Terrabutler installation: /usr/share/terrabutler.
+Do you want to replace it? [y/N]
+
+

Just press y and press enter and Terrabutler should be updated to the version that you downloaded.

+
+Danger +

In case you have installed the Terrabutler earlier with different locations, you will need to pass them, otherwise the +install script won't prompt you to update it.

+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/new-site/index.html b/new-site/index.html new file mode 100644 index 00000000..6ee49a33 --- /dev/null +++ b/new-site/index.html @@ -0,0 +1,668 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Add New Site - Terrabutler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + +

Add a new site

+

Create a new directory

+

In the project folder root, create a new diretory called site_<site-name>:

+
$ mkdir site_<site-name>
+
+
+Tip +
+

Replace <site-name> with your new site name!

+

Configure the new site

+

Add the new site to site_inception variables file

+

Add <site-name> to the following file, in inception_projects = [] line:

+
./configs/variables/<project>-<env>-inception.tfvars
+
+

Add the new site to Terrabutler settings

+

Add <site-name> to the following file, in sites: ordered: - <site-name> line:

+
./configs/settings.yml
+
+

Add a new variable file to the Variables Folder

+

Create a new file called <project-name>-<env>-<site-name>.tfvars to the following directory:

+
./configs/variables/<project-name>-<env>-<site-name>.tfvars
+
+

Perform an apply in site_inception

+

Run the following command, to update the new configuration on site_inception:

+
$ terrabutler tf -site inception apply
+
+

Add files to the new site

+

Add terraform files

+

Run the following commands to copy the following Terraform files to the site_<site-name>:

+
$ cd site_<site-name>
+
+
$ cp ../site_inception/terraform.tf .
+
+
$ cp ../site_inception/provider.tf .
+
+ +

Run the following commands to create the Symbolic Links:

+
$ cd site_<site-name>
+
+

$ ln -s ../globals/data.tf ./data_global.tf
+
+
$ ln -s ../globals/locals.tf ./locals_globals.tf
+
+
$ ln -s ../globals/variables.tf ./variables_globals.tf
+

+

Perform an init in the new site

+

Run the following command:

+
$ terrabutler tf -site data init 
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/philosophy/index.html b/philosophy/index.html new file mode 100644 index 00000000..c1aef144 --- /dev/null +++ b/philosophy/index.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Philosophy - Terrabutler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Philosophy

+

Before settling for Terrabutler, it's a good idea to understand the philosophy behind the project, +in order to make sure it aligns with your goals. This page explains the problem and the solution.

+

Problem

+

All our IaC projects are backed by Terraform. Instead of having a folder with every resource, we have +created different folders that have resources from the same category, and we call them sites. For +example inside the network site we will have the creation of VPC, SG and WAF, so this site is +where we have all the resources related to network. By splitting the code into various sites we have +smaller plans and it's more easy to manage the code. By having all the code divided into various sites +it's a bit more difficult to manage all the terraform variable files. And we wanted all of this for each +environment, so it needs to be divided into different environments, for example production and development. +All of the sites state needs to be have a remote state and with a lock function, to prevent usage at the same +time.

+

Solution

+

Create a IaC with the inception site that will be responsible to manage the project environments via Terraform +workspaces tool and where the backends for each site will be created. Use Terrabutler to manage all the IAC +between all the sites.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/requirements/index.html b/requirements/index.html new file mode 100644 index 00000000..26e09837 --- /dev/null +++ b/requirements/index.html @@ -0,0 +1,504 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Requirements - Terrabutler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Requirements

+

Before you start using you will need to have some tools installed.

+ +

These tools are required to be installed for a Terrabutler to work properly.

+
+Danger +
+

This repository only works on Intel based Processors (x86/x64). Arm/Arm64 or another processor architectures are incompatible!

+

Installing requirements

+

In the list below you have the install instruction for each tool:

+ +

After checking requirements

+

You can now proceed to the installation process of Terrabutler.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 00000000..f10e230e --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":""},{"location":"#terrabutler","title":"Terrabutler","text":"

The utility that helps keeping your IaC in one piece

"},{"location":"#what-is-terrabutler","title":"What is Terrabutler?","text":"

Terrabutler is a wrapper written in Python that helps maintaining IaC (Infrastructure as code) projects using Terraform by managing the environments.

"},{"location":"create-project/","title":"Create a new project","text":"

Before proceeding make sure that you have followed the Installation.

"},{"location":"create-project/#configure-direnv","title":"Configure direnv","text":"

For direnv to work properly it needs to be hooked into the shell. Check direnv docs to know more: https://direnv.net/docs/hook.html

Make sure that you have followed direnv documentation before proceeding.

"},{"location":"create-project/#configure-terrabutler","title":"Configure Terrabutler","text":""},{"location":"create-project/#create-your-project-folder","title":"Create your project folder","text":"
mkdir <project_name>\n
"},{"location":"create-project/#download-template","title":"Download Template","text":"

Start by downloading the Terrabutler Template Project from the repository source below:

Copy the files inside ./terrabutler-template/ to the root of your project folder.

$ cp -a /terrabutler-template/. /<project_name>/\n
"},{"location":"create-project/#create-a-new-workspace","title":"Create a new workspace","text":"

Before configuring terrabutler, inside <project_name>/site_inception folder, you will need to create a Terraform Workspace: For example, we are gonna call it \"staging\"

$ cd site_inception\n$ terraform workspace new staging\n
"},{"location":"create-project/#change-variables","title":"Change Variables","text":"

Run the script ./<project_name>/config_template.sh, with the following arguments, located inside the project folder root:

$ ./config_template.sh -d <domain> -e <environment_name> -p <project_name>\n\nUSAGE:\n   ./config_template [FLAG] [STRING]\nFLAGS:\n   -o <organization_name>   The name for your organization.  Example: -o example\n\n-d <domain>              The domain of your organization. Example: -d example.com\n\n-e <environment_name>    The environment name of your organization. Example: -e staging\n
Danger

This script only works with the template folder! Don't use it in another project folders! ./terrabutler-template/config_template.sh

"},{"location":"create-project/#terraform","title":"Terraform","text":"

Start by installing Terraform with tfenv:

$ tfenv install 
"},{"location":"create-project/#initialize-the-project","title":"Initialize the Project","text":"

Perform an Terraform Initialization inside site_inception:

$ cd /site_inception/\n$ terraform init\n
Perform an Terraform Apply with the .tfvars inside /config/variables/:

./configs/variables/global.tfvars ./configs/variables/<project_name>-<environment_name>.tfvars\" ./configs/variables/<project_name>-<environment_name>-inception.tfvars\"

$ terraform apply -var-file=\"../configs/variables/global.tfvars\" -var-file=\"../configs/variables/<project_name>-<environment_name>.tfvars\" -var-file=\"../configs/variables/<project_name>-<environment_name>-inception.tfvars\"\n
"},{"location":"create-project/#change-local-to-remote-backend","title":"Change local to remote backend","text":""},{"location":"create-project/#uncomment-the-remote-backend-line","title":"Uncomment the remote backend line","text":"

Remove the commented line as below, in the terrabutler-template in the path ./site-inception/terraform.tf to change from local to remote.

backend \"s3\" {}\n

Perform an Terraform initialization with the backend config file,located in /configs/backend/ to update the new changes:

$ terraform init -backend-config=<inception_backend_path>  
Tip

Example: $ terraform init -backend-config=\"./configs/backends/--inception.tfvars\""},{"location":"create-project/#delete-the-local-state","title":"Delete the local state","text":"

Delete the local state in /site_inception, as it is not necessary:

$ rm -rf terraform.tfstate.d/ terraform.tfstate terraform.tfstate.backup\n
"},{"location":"create-project/#terrabutler-commands","title":"Terrabutler commands","text":""},{"location":"create-project/#terrabutler-plan","title":"Terrabutler Plan","text":"

Perform an Terrabutler Plan to ensure everything is ok, and plan any changes:

$ terrabutler tf -site inception plan\n
"},{"location":"create-project/#terrabutler-apply","title":"Terrabutler Apply","text":"

Perform an Terrabutler Apply to apply the planned changes:

$ terrabutler tf -site inception apply\n
"},{"location":"create-project/#terrabutler-destroy","title":"Terrabutler Destroy","text":"

Perform an Terrabutler Destroy to delete or undo any changes made in the provider:

$ terrabutler tf -site inception destroy\n
"},{"location":"installation/","title":"Installation","text":"

Before proceeding make sure that you have the requirements.

"},{"location":"installation/#download-the-binaries-and-extract-them","title":"Download the binaries and extract them","text":"

All the binaries versions are available inside the releases pages

To download the latest binaries run the following command:

wget -qO- https://github.com/montblu/terrabutler/releases/download/<VERSION>/terrabutler-<OS>-<ARCH>-<VERSION>.tar.gz | tar -zxvf - terrabutler\n

Where <VERSION> is the version of the release.

For example, to download Terrabutler v0.2.0 for Linux x64, just run:

wget -qO- https://github.com/montblu/terrabutler/releases/download/v0.2.0/terrabutler-linux-x64-v0.2.0.tar.gz | tar -zxvf - terrabutler\n
"},{"location":"installation/#install-the-binaries","title":"Install the binaries","text":"

To install the binaries into your system simply run the installer script inside the terrabutler folder:

sudo terrabutler/install\n

All the binaries will be placed inside the /usr/share/terrabutler folder and the bin inside the /usr/bin folder

Tip

If you wanna set the location where terrabutler will be installed you can define it by passing arguments when running the install script. This arguments can be seen by running:

terrabutler/install -h\n

Example of installing for local user only (no need to run the install script as sudo):

terrabutler/install -i ~/.local/share/terrabutler -b ~/.local/bin\n
"},{"location":"installation/#check-if-the-installation-was-successful","title":"Check if the installation was successful","text":"

You should be able to run:

terrabutler --version\n

and the output should be:

Terrabutler: v0.2.0\n

If the output is not similar to the one above, then something went wrong during the installation.

"},{"location":"installation/#how-to-update-to-a-newer-version","title":"How to update to a newer version?","text":"

If you have Terrabutler already installed and want to update to a newer version just do all the installation process again. When you will be running the installer script it should prompt if you want to upgrade the Terrabutler, as we can see below:

Found preexisting Terrabutler installation: /usr/share/terrabutler.\nDo you want to replace it? [y/N]\n

Just press y and press enter and Terrabutler should be updated to the version that you downloaded.

Danger

In case you have installed the Terrabutler earlier with different locations, you will need to pass them, otherwise the install script won't prompt you to update it.

"},{"location":"new-site/","title":"Add a new site","text":""},{"location":"new-site/#create-a-new-directory","title":"Create a new directory","text":"

In the project folder root, create a new diretory called site_<site-name>:

$ mkdir site_<site-name>\n
Tip

Replace <site-name> with your new site name!

"},{"location":"new-site/#configure-the-new-site","title":"Configure the new site","text":""},{"location":"new-site/#add-the-new-site-to-site_inception-variables-file","title":"Add the new site to site_inception variables file","text":"

Add <site-name> to the following file, in inception_projects = [] line:

./configs/variables/<project>-<env>-inception.tfvars\n
"},{"location":"new-site/#add-the-new-site-to-terrabutler-settings","title":"Add the new site to Terrabutler settings","text":"

Add <site-name> to the following file, in sites: ordered: - <site-name> line:

./configs/settings.yml\n
"},{"location":"new-site/#add-a-new-variable-file-to-the-variables-folder","title":"Add a new variable file to the Variables Folder","text":"

Create a new file called <project-name>-<env>-<site-name>.tfvars to the following directory:

./configs/variables/<project-name>-<env>-<site-name>.tfvars\n
"},{"location":"new-site/#perform-an-apply-in-site_inception","title":"Perform an apply in site_inception","text":"

Run the following command, to update the new configuration on site_inception:

$ terrabutler tf -site inception apply\n
"},{"location":"new-site/#add-files-to-the-new-site","title":"Add files to the new site","text":""},{"location":"new-site/#add-terraform-files","title":"Add terraform files","text":"

Run the following commands to copy the following Terraform files to the site_<site-name>:

$ cd site_<site-name>\n
$ cp ../site_inception/terraform.tf .\n
$ cp ../site_inception/provider.tf .\n
"},{"location":"new-site/#create-symbolic-links","title":"Create Symbolic Links","text":"

Run the following commands to create the Symbolic Links:

$ cd site_<site-name>\n

$ ln -s ../globals/data.tf ./data_global.tf\n
$ ln -s ../globals/locals.tf ./locals_globals.tf\n
$ ln -s ../globals/variables.tf ./variables_globals.tf\n

"},{"location":"new-site/#perform-an-init-in-the-new-site","title":"Perform an init in the new site","text":"

Run the following command:

$ terrabutler tf -site data init 
"},{"location":"philosophy/","title":"Philosophy","text":"

Before settling for Terrabutler, it's a good idea to understand the philosophy behind the project, in order to make sure it aligns with your goals. This page explains the problem and the solution.

"},{"location":"philosophy/#problem","title":"Problem","text":"

All our IaC projects are backed by Terraform. Instead of having a folder with every resource, we have created different folders that have resources from the same category, and we call them sites. For example inside the network site we will have the creation of VPC, SG and WAF, so this site is where we have all the resources related to network. By splitting the code into various sites we have smaller plans and it's more easy to manage the code. By having all the code divided into various sites it's a bit more difficult to manage all the terraform variable files. And we wanted all of this for each environment, so it needs to be divided into different environments, for example production and development. All of the sites state needs to be have a remote state and with a lock function, to prevent usage at the same time.

"},{"location":"philosophy/#solution","title":"Solution","text":"

Create a IaC with the inception site that will be responsible to manage the project environments via Terraform workspaces tool and where the backends for each site will be created. Use Terrabutler to manage all the IAC between all the sites.

"},{"location":"requirements/","title":"Requirements","text":"

Before you start using you will need to have some tools installed.

  • direnv
  • tfenv

These tools are required to be installed for a Terrabutler to work properly.

Danger

This repository only works on Intel based Processors (x86/x64). Arm/Arm64 or another processor architectures are incompatible!

"},{"location":"requirements/#installing-requirements","title":"Installing requirements","text":"

In the list below you have the install instruction for each tool:

  • direnv
  • tfenv
"},{"location":"requirements/#after-checking-requirements","title":"After checking requirements","text":"

You can now proceed to the installation process of Terrabutler.

"},{"location":"usage/","title":"Basic Usage","text":"

In this section we quickly cover the basic commands of Terrabutler. The usage of it can always be seen by using the help menu inside of every command or subcommand.

Example:

terrabutler tf -site inception apply --help\n

The command above shows all the arguments and options that can be used when running that command.

"},{"location":"usage/#usage","title":"Usage","text":"
terrabutler [global options] command [subcommand] [arguments] [options]\n
"},{"location":"usage/#global-options","title":"Global options","text":"

All global options can be placed at the command level.

  • --help, -help, -h: Show help menu.
  • --version, -version: Show version of Terrabutler.
"},{"location":"usage/#commands","title":"Commands","text":"

The commands are:

  • env: Manage environments
  • init: Initialize the manager
  • tf: Manage terraform commands
"},{"location":"usage/#command-env","title":"Command env","text":"

Subcommands:

  • delete: \"Delete an environment\"
  • list: \"List environments\"
  • new: \"Create a new environment\"
  • reload: \"Reload the current environment\"
  • select: \"Select a environment\"
  • show: \"Show the name of the current environment\"

Example:

terrabutler env select staging\n

The command above change the current environment to staging.

"},{"location":"usage/#command-tf","title":"Command tf","text":"Tip

The tf subcommands are the Terraform commands

Subcommands:

  • apply: \"Create or update infrastructure\"
  • console: \"Try Terraform expressions at an interactive command...\"
  • destroy: \"Prepare your working directory for other commands\"
  • fmt: \"Reformat your configuration in the standardstyle\"
  • force-unlock: \"Release a stuck lock on the current workspace\"
  • generate-options: \"Generate terraform options\"
  • import: \"Associate existing infrastructure with a Terraform...\"
  • init: \"Prepare your working directory for other commands\"
  • output: \"Show output values from your root module\"
  • plan: \"Show changes required by the current configuration\"
  • providers: \"Show the providers required for this configuration\"
  • refresh: \"Update the state to match remote systems\"
  • show: \"Show the current state or a saved plan\"
  • state: \"Advanced state management\"
  • taint: \"Mark a resource instance as not fully functional\"
  • untaint: \"Remove the 'tainted' state from a resource instance\"
  • validate: \"Validate the configuration files\"
  • version: \"Show the current Terraform version\"

Example:

terrabutler tf -site inception apply\n

The command above run a terraform apply command inside the site inception in the current environment.

"},{"location":"usage/#command-init","title":"Command init","text":"

Has no subcommands

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..2acae104 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,38 @@ + + + + https://docs.montblu.eu/terrabutler/ + 2024-03-05 + daily + + + https://docs.montblu.eu/terrabutler/create-project/ + 2024-03-05 + daily + + + https://docs.montblu.eu/terrabutler/installation/ + 2024-03-05 + daily + + + https://docs.montblu.eu/terrabutler/new-site/ + 2024-03-05 + daily + + + https://docs.montblu.eu/terrabutler/philosophy/ + 2024-03-05 + daily + + + https://docs.montblu.eu/terrabutler/requirements/ + 2024-03-05 + daily + + + https://docs.montblu.eu/terrabutler/usage/ + 2024-03-05 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 00000000..fa0b3963 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/usage/index.html b/usage/index.html new file mode 100644 index 00000000..ab1345bf --- /dev/null +++ b/usage/index.html @@ -0,0 +1,625 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Basic Usage - Terrabutler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + +

Basic Usage

+

In this section we quickly cover the basic commands of Terrabutler. +The usage of it can always be seen by using the help menu inside of every +command or subcommand.

+

Example:

+
terrabutler tf -site inception apply --help
+
+

The command above shows all the arguments and options that can be used when +running that command.

+

Usage

+
terrabutler [global options] command [subcommand] [arguments] [options]
+
+

Global options

+

All global options can be placed at the command level.

+
    +
  • --help, -help, -h: Show help menu.
  • +
  • --version, -version: Show version of Terrabutler.
  • +
+

Commands

+

The commands are:

+
    +
  • env: Manage environments
  • +
  • init: Initialize the manager
  • +
  • tf: Manage terraform commands
  • +
+

Command env

+

Subcommands:

+
    +
  • delete: "Delete an environment"
  • +
  • list: "List environments"
  • +
  • new: "Create a new environment"
  • +
  • reload: "Reload the current environment"
  • +
  • select: "Select a environment"
  • +
  • show: "Show the name of the current environment"
  • +
+

Example:

+
terrabutler env select staging
+
+

The command above change the current environment to staging.

+

Command tf

+
+Tip +

The tf subcommands are the Terraform commands

+
+

Subcommands:

+
    +
  • apply: "Create or update infrastructure"
  • +
  • console: "Try Terraform expressions at an interactive command..."
  • +
  • destroy: "Prepare your working directory for other commands"
  • +
  • fmt: "Reformat your configuration in the standardstyle"
  • +
  • force-unlock: "Release a stuck lock on the current workspace"
  • +
  • generate-options: "Generate terraform options"
  • +
  • import: "Associate existing infrastructure with a Terraform..."
  • +
  • init: "Prepare your working directory for other commands"
  • +
  • output: "Show output values from your root module"
  • +
  • plan: "Show changes required by the current configuration"
  • +
  • providers: "Show the providers required for this configuration"
  • +
  • refresh: "Update the state to match remote systems"
  • +
  • show: "Show the current state or a saved plan"
  • +
  • state: "Advanced state management"
  • +
  • taint: "Mark a resource instance as not fully functional"
  • +
  • untaint: "Remove the 'tainted' state from a resource instance"
  • +
  • validate: "Validate the configuration files"
  • +
  • version: "Show the current Terraform version"
  • +
+

Example:

+
terrabutler tf -site inception apply
+
+

The command above run a terraform apply command inside the site inception in +the current environment.

+

Command init

+

Has no subcommands

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file