Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • cloud/documentation
  • 242618/documentation
  • 469240/documentation
  • LukasD/documentation
  • 35475/documentation
  • 323969/documentation
6 results
Show changes
Commits on Source (155)
Showing
with 943 additions and 0 deletions
.publictmp/
.hugo_build.lock
\ No newline at end of file
image: registry.gitlab.com/pages/hugo:latest
variables:
GIT_SUBMODULE_STRATEGY: recursive
SSH_PORT: 22202
build-test:
before_script: &before-script-build-deploy
- apk update
- apk add git python3 py3-pip py3-yaml openssh-client curl moreutils
script:
- hugo --config config.toml -D --destination=./public
deploy_cpanel:
before_script: *before-script-build-deploy
script:
- git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.ics.muni.cz/cloud/hiera.git
- sed -i '11,$d' content/cloud/flavors/index.md
- echo "{{< csv-table header=\"true\">}}" >> content/cloud/flavors/index.md
- python3 ci/flavor_info_miner.py --hiera-file ./hiera/group/ostack/flavors.yaml --output-file flavors.csv
- cat flavors.csv >> content/cloud/flavors/index.md
- echo "{{</csv-table>}}" >> content/cloud/flavors/index.md
- cat content/cloud/flavors/index.md
- sed -i -e "s/BUILDIDTAG/$CI_COMMIT_SHORT_SHA/g" ./layouts/partials/site-footer.html
- curl https://cloud.gitlab-pages.ics.muni.cz/image-rotation/image-rotation-journal.md >> content/cloud/image-rotation/index.md
- grep -v "# Image rotation news" content/cloud/image-rotation/index.md | sponge content/cloud/image-rotation/index.md
- python3 ci/image_rotation_news_gen.py
- hugo --config config.toml -D --destination=./public
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY_cpanel" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo "$SSH_KNOWN_HOSTS_cpanel" >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
- ssh -p ${SSH_PORT} docscloudmuni@docs.cloud.muni.cz 'mkdir ~/tmpdeploy'
- scp -P ${SSH_PORT} -r ./public/* docscloudmuni@docs.cloud.muni.cz:~/tmpdeploy
- ssh -p ${SSH_PORT} docscloudmuni@docs.cloud.muni.cz 'mv ~/public_html ~/todelete && mv ~/tmpdeploy ~/public_html && rm -rf ~/todelete'
- sleep 5
- latest_commit=$(git log -1 --pretty=format:%h )
- "curl -H 'Cache-Control: no-cache' https://docs.cloud.muni.cz | grep $latest_commit"
only:
- master
# Metacentrum Cloud Documentation
**Note that this documentation is getting obsolete, use [e-infra_cz doc repo](https://gitlab.ics.muni.cz/einfra-docs/documentation) instead.**
## Run development server
```
hugo serve --config config-dev.toml --bind 127.0.0.1 --port 1313
```
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---
/*
SortTable
version 2
7th April 2007
Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
Instructions:
Download this file
Add <script src="sorttable.js"></script> to your HTML
Add class="sortable" to any table you'd like to make sortable
Click on the headers to sort
Thanks to many, many people for contributions and suggestions.
Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
This basically means: do what you want with it.
*/
var stIsIE = /*@cc_on!@*/false;
sorttable = {
init: function() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
if (!document.createElement || !document.getElementsByTagName) return;
sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
forEach(document.getElementsByTagName('table'), function(table) {
if (table.className.search(/\bsortable\b/) != -1) {
sorttable.makeSortable(table);
}
});
},
makeSortable: function(table) {
if (table.getElementsByTagName('thead').length == 0) {
// table doesn't have a tHead. Since it should have, create one and
// put the first table row in it.
the = document.createElement('thead');
the.appendChild(table.rows[0]);
table.insertBefore(the,table.firstChild);
}
// Safari doesn't support table.tHead, sigh
if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
if (table.tHead.rows.length != 1) return; // can't cope with two header rows
// Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
// "total" rows, for example). This is B&R, since what you're supposed
// to do is put them in a tfoot. So, if there are sortbottom rows,
// for backwards compatibility, move them to tfoot (creating it if needed).
sortbottomrows = [];
for (var i=0; i<table.rows.length; i++) {
if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
sortbottomrows[sortbottomrows.length] = table.rows[i];
}
}
if (sortbottomrows) {
if (table.tFoot == null) {
// table doesn't have a tfoot. Create one.
tfo = document.createElement('tfoot');
table.appendChild(tfo);
}
for (var i=0; i<sortbottomrows.length; i++) {
tfo.appendChild(sortbottomrows[i]);
}
delete sortbottomrows;
}
// work through each column and calculate its type
headrow = table.tHead.rows[0].cells;
for (var i=0; i<headrow.length; i++) {
// manually override the type with a sorttable_type attribute
if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
if (mtch) { override = mtch[1]; }
if (mtch && typeof sorttable["sort_"+override] == 'function') {
headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
} else {
headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
}
// make it clickable to sort
headrow[i].sorttable_columnindex = i;
headrow[i].sorttable_tbody = table.tBodies[0];
dean_addEvent(headrow[i],"click", sorttable.innerSortFunction = function(e) {
if (this.className.search(/\bsorttable_sorted\b/) != -1) {
// if we're already sorted by this column, just
// reverse the table, which is quicker
sorttable.reverse(this.sorttable_tbody);
this.className = this.className.replace('sorttable_sorted',
'sorttable_sorted_reverse');
this.removeChild(document.getElementById('sorttable_sortfwdind'));
sortrevind = document.createElement('span');
sortrevind.id = "sorttable_sortrevind";
sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
this.appendChild(sortrevind);
return;
}
if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
// if we're already sorted by this column in reverse, just
// re-reverse the table, which is quicker
sorttable.reverse(this.sorttable_tbody);
this.className = this.className.replace('sorttable_sorted_reverse',
'sorttable_sorted');
this.removeChild(document.getElementById('sorttable_sortrevind'));
sortfwdind = document.createElement('span');
sortfwdind.id = "sorttable_sortfwdind";
sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
this.appendChild(sortfwdind);
return;
}
// remove sorttable_sorted classes
theadrow = this.parentNode;
forEach(theadrow.childNodes, function(cell) {
if (cell.nodeType == 1) { // an element
cell.className = cell.className.replace('sorttable_sorted_reverse','');
cell.className = cell.className.replace('sorttable_sorted','');
}
});
sortfwdind = document.getElementById('sorttable_sortfwdind');
if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
sortrevind = document.getElementById('sorttable_sortrevind');
if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
this.className += ' sorttable_sorted';
sortfwdind = document.createElement('span');
sortfwdind.id = "sorttable_sortfwdind";
sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
this.appendChild(sortfwdind);
// build an array to sort. This is a Schwartzian transform thing,
// i.e., we "decorate" each row with the actual sort key,
// sort based on the sort keys, and then put the rows back in order
// which is a lot faster because you only do getInnerText once per row
row_array = [];
col = this.sorttable_columnindex;
rows = this.sorttable_tbody.rows;
for (var j=0; j<rows.length; j++) {
row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
}
/* If you want a stable sort, uncomment the following line */
//sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
/* and comment out this one */
row_array.sort(this.sorttable_sortfunction);
tb = this.sorttable_tbody;
for (var j=0; j<row_array.length; j++) {
tb.appendChild(row_array[j][1]);
}
delete row_array;
});
}
}
},
guessType: function(table, column) {
// guess the type of a column based on its first non-blank row
sortfn = sorttable.sort_alpha;
for (var i=0; i<table.tBodies[0].rows.length; i++) {
text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
if (text != '') {
if (text.match(/^-?[$]?[\d,.]+%?$/)) {
return sorttable.sort_numeric;
}
// check for a date: dd/mm/yyyy or dd/mm/yy
// can have / or . or - as separator
// can be mm/dd as well
possdate = text.match(sorttable.DATE_RE)
if (possdate) {
// looks like a date
first = parseInt(possdate[1]);
second = parseInt(possdate[2]);
if (first > 12) {
// definitely dd/mm
return sorttable.sort_ddmm;
} else if (second > 12) {
return sorttable.sort_mmdd;
} else {
// looks like a date, but we can't tell which, so assume
// that it's dd/mm (English imperialism!) and keep looking
sortfn = sorttable.sort_ddmm;
}
}
}
}
return sortfn;
},
getInnerText: function(node) {
// gets the text we want to use for sorting for a cell.
// strips leading and trailing whitespace.
// this is *not* a generic getInnerText function; it's special to sorttable.
// for example, you can override the cell text with a customkey attribute.
// it also gets .value for <input> fields.
if (!node) return "";
hasInputs = (typeof node.getElementsByTagName == 'function') &&
node.getElementsByTagName('input').length;
if (node.getAttribute("sorttable_customkey") != null) {
return node.getAttribute("sorttable_customkey");
}
else if (typeof node.textContent != 'undefined' && !hasInputs) {
return node.textContent.replace(/^\s+|\s+$/g, '');
}
else if (typeof node.innerText != 'undefined' && !hasInputs) {
return node.innerText.replace(/^\s+|\s+$/g, '');
}
else if (typeof node.text != 'undefined' && !hasInputs) {
return node.text.replace(/^\s+|\s+$/g, '');
}
else {
switch (node.nodeType) {
case 3:
if (node.nodeName.toLowerCase() == 'input') {
return node.value.replace(/^\s+|\s+$/g, '');
}
case 4:
return node.nodeValue.replace(/^\s+|\s+$/g, '');
break;
case 1:
case 11:
var innerText = '';
for (var i = 0; i < node.childNodes.length; i++) {
innerText += sorttable.getInnerText(node.childNodes[i]);
}
return innerText.replace(/^\s+|\s+$/g, '');
break;
default:
return '';
}
}
},
reverse: function(tbody) {
// reverse the rows in a tbody
newrows = [];
for (var i=0; i<tbody.rows.length; i++) {
newrows[newrows.length] = tbody.rows[i];
}
for (var i=newrows.length-1; i>=0; i--) {
tbody.appendChild(newrows[i]);
}
delete newrows;
},
/* sort functions
each sort function takes two parameters, a and b
you are comparing a[0] and b[0] */
sort_numeric: function(a,b) {
aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
if (isNaN(aa)) aa = 1000000;
bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
if (isNaN(bb)) bb = 1000000;
return aa-bb;
},
sort_alpha: function(a,b) {
if (a[0] == "Unlimited") { a[0] = 1000000}
if (b[0] == "Unlimited") { b[0] = 1000000}
if (a[0]==b[0]) return 0;
if (a[0]<b[0]) return -1;
return 1;
},
sort_ddmm: function(a,b) {
mtch = a[0].match(sorttable.DATE_RE);
y = mtch[3]; m = mtch[2]; d = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt1 = y+m+d;
mtch = b[0].match(sorttable.DATE_RE);
y = mtch[3]; m = mtch[2]; d = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt2 = y+m+d;
if (dt1==dt2) return 0;
if (dt1<dt2) return -1;
return 1;
},
sort_mmdd: function(a,b) {
mtch = a[0].match(sorttable.DATE_RE);
y = mtch[3]; d = mtch[2]; m = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt1 = y+m+d;
mtch = b[0].match(sorttable.DATE_RE);
y = mtch[3]; d = mtch[2]; m = mtch[1];
if (m.length == 1) m = '0'+m;
if (d.length == 1) d = '0'+d;
dt2 = y+m+d;
if (dt1==dt2) return 0;
if (dt1<dt2) return -1;
return 1;
},
shaker_sort: function(list, comp_func) {
// A stable sort function to allow multi-level sorting of data
// see: http://en.wikipedia.org/wiki/Cocktail_sort
// thanks to Joseph Nahmias
var b = 0;
var t = list.length - 1;
var swap = true;
while(swap) {
swap = false;
for(var i = b; i < t; ++i) {
if ( comp_func(list[i], list[i+1]) > 0 ) {
var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
swap = true;
}
} // for
t--;
if (!swap) break;
for(var i = t; i > b; --i) {
if ( comp_func(list[i], list[i-1]) < 0 ) {
var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
swap = true;
}
} // for
b++;
} // while(swap)
}
}
/* ******************************************************************
Supporting functions: bundled here to avoid depending on a library
****************************************************************** */
// Dean Edwards/Matthias Miller/John Resig
/* for Mozilla/Opera9 */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", sorttable.init, false);
}
/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
sorttable.init(); // call the onload handler
}
};
/*@end @*/
/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
sorttable.init(); // call the onload handler
}
}, 10);
}
/* for other browsers */
window.onload = sorttable.init;
// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini
// http://dean.edwards.name/weblog/2005/10/add-event/
function dean_addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
// assign each event handler a unique ID
if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
// create a hash table of event types for the element
if (!element.events) element.events = {};
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one)
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};
// a counter used to create unique IDs
dean_addEvent.guid = 1;
function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};
function handleEvent(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
// get a reference to the hash table of event handlers
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
this.$$handleEvent = handlers[i];
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};
function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
}
// Dean's forEach: http://dean.edwards.name/base/forEach.js
/*
forEach, version 1.0
Copyright 2006, Dean Edwards
License: http://www.opensource.org/licenses/mit-license.php
*/
// array-like enumeration
if (!Array.forEach) { // mozilla already supports this
Array.forEach = function(array, block, context) {
for (var i = 0; i < array.length; i++) {
block.call(context, array[i], i, array);
}
};
}
// generic enumeration
Function.prototype.forEach = function(object, block, context) {
for (var key in object) {
if (typeof this.prototype[key] == "undefined") {
block.call(context, object[key], key, object);
}
}
};
// character enumeration
String.forEach = function(string, block, context) {
Array.forEach(string.split(""), function(chr, index) {
block.call(context, chr, index, string);
});
};
// globally resolve forEach enumeration
var forEach = function(object, block, context) {
if (object) {
var resolve = Object; // default
if (object instanceof Function) {
// functions have a "length" property
resolve = Function;
} else if (object.forEach instanceof Function) {
// the object implements a custom forEach method so use that
object.forEach(block, context);
return;
} else if (typeof object == "string") {
// the object is a string
resolve = String;
} else if (typeof object.length == "number") {
// the object is array-like
resolve = Array;
}
resolve.forEach(object, block, context);
}
};
#!/usr/bin/env python3
"""
Script generates CSV output with available flavors
Actions performed:
generating info about available flavors we offer
* if everything goes well
- flavor section is updated according to hiera repo stats
Usage:
python3 ./flavor_info_miner.py --hiera-file flavors.yaml
"""
import csv
import argparse
import yaml
COLUMN_NAMES = [
"Flavor name",
"CPU",
"RAM (in GB)",
"HPC",
"SSD",
"Disc throughput (in MB per second)",
"IOPS",
"Net average throughput (in MB per second)",
"GPU",
]
FLAVOR_BLACKLIST = [
"cerit.hde-half",
"cerit.hde",
"meta.mema2",
"csirtmu.tiny1x2",
"csirtmu.tiny1x4",
"csirtmu.small2x4",
"csirtmu.small2x8",
"csirtmu.medium4x8",
"csirtmu.medium4x16",
"csirtmu.large8x16",
"csirtmu.large4x32",
"csirtmu.large8x32",
"csirtmu.jumbo16x32",
"csirtmu.jumbo8x64",
"csirtmu.jumbo16x64",
"du.perftest",
"admin.scaletest",
"hpc.18core-64ram-dukan",
"hpc.8core-32ram-dukan",
]
def get_hiera_flavors(hiera_file):
"""Opens and extracts data from hiera file"""
with open(hiera_file, "r", encoding="utf-8") as hiera_file_h:
data = yaml.safe_load(hiera_file_h)
return data["cloud::profile::kolla::nova::controller::os_flavors"]
def filter_flavors(all_flavors):
"""Filters and excludes blacklisted and deprecated flavors"""
filtered_flavors = []
for flavor in all_flavors:
if (
flavor["name"] not in FLAVOR_BLACKLIST
and "deprecated" not in flavor["name"]
):
filtered_flavors.append(flavor)
return filtered_flavors
def generate_flavor_data(filtered_flavors):
"""Generates CSV output from extracted data"""
output = []
for flavor in filtered_flavors:
name = flavor["name"]
vcpus = flavor["vcpus"]
ram = flavor["ram"] / 1024
disk = (
flavor["extra_specs"]["quota:disk_total_bytes_sec"] / 1000000
if "quota:disk_total_bytes_sec" in flavor["extra_specs"]
else "Unlimited"
)
net = (
flavor["extra_specs"]["quota:vif_outbound_average"] / 1000
if "quota:vif_outbound_average" in flavor["extra_specs"]
else "Unlimited"
)
iops = (
flavor["extra_specs"]["quota:disk_total_iops_sec"]
if "quota:disk_total_iops_sec" in flavor["extra_specs"]
else "Unlimited"
)
if (
"aggregate_instance_extra_specs:hpc" not in flavor["extra_specs"]
or flavor["extra_specs"]["aggregate_instance_extra_specs:hpc"] == "false"
):
hpc = "No"
else:
hpc = "Yes"
if (
"aggregate_instance_extra_specs:ssd" not in flavor["extra_specs"]
or flavor["extra_specs"]["aggregate_instance_extra_specs:ssd"] == "false"
):
ssd = "No"
else:
ssd = "Yes"
if (
"pci_passthrough:alias" not in flavor["extra_specs"]
or "gpu" not in flavor["extra_specs"]["pci_passthrough:alias"]
):
gpu = "No"
else:
gpu = "Yes"
output.append(
[
f"{name}",
f"{vcpus}",
f"{ram:.0f}",
f"{hpc}",
f"{ssd}",
f"{disk}",
f"{iops}",
f"{net}",
f"{gpu}",
]
)
return output
def write_output_to_file(output, output_file):
"""Writed generated output into file"""
with open(output_file, "w", newline="") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=COLUMN_NAMES)
writer.writeheader()
for row in output:
# ['Flavor name' , 'CPU' , 'RAM (in GB)' , 'HPC' , 'SSD' , 'Disc throughput (in MB per second)' , 'IOPS', 'Net average througput (in MB per second)', 'GPU']
writer.writerow(
{
COLUMN_NAMES[0]: row[0],
COLUMN_NAMES[1]: row[1],
COLUMN_NAMES[2]: row[2],
COLUMN_NAMES[3]: row[3],
COLUMN_NAMES[4]: row[4],
COLUMN_NAMES[5]: row[5],
COLUMN_NAMES[6]: row[6],
COLUMN_NAMES[7]: row[7],
COLUMN_NAMES[8]: row[8],
}
)
if __name__ == "__main__":
PARSER = argparse.ArgumentParser(
description="This script generates table with flavor info."
)
PARSER.add_argument(
"--hiera-file", type=str, required=True, help="Path for hiera file flavors.yaml"
)
PARSER.add_argument(
"--output-file", type=str, required=True, help="Path for output file"
)
ARGS = PARSER.parse_args()
ALL_FLAVORS = get_hiera_flavors(ARGS.hiera_file)
FILTERED_FLAVORS = filter_flavors(ALL_FLAVORS)
OUTPUT = generate_flavor_data(FILTERED_FLAVORS)
write_output_to_file(OUTPUT, ARGS.output_file)
#!/usr/bin/env python3
"""
Script generates dynamically image rotation news updates
Actions performed:
generating of image rotation news
* if everything goes well
- image rotation news section is updated according to image rotation journal
Usage:
python3 ./image_rotation_news.gen.py
"""
import re
import datetime
DOC_NEWS_FILE = "content/cloud/news/index.md"
IMAGE_ROTATION_FILE = "content/cloud/image-rotation/index.md"
def get_image_update_log_dates():
"""Gets all image rotation update dates"""
with open(IMAGE_ROTATION_FILE, "r", encoding="utf-8") as rotate_file:
file_content = rotate_file.read()
return re.findall(
r"## Image rotation update from [0-9]{4}-[0-9]{2}-[0-9]{2}:", file_content
)
def generate_news(image_update_dates):
"""Generates news with image update news"""
with open(DOC_NEWS_FILE, "r", encoding="utf-8") as news_file:
news_content = news_file.readlines()
news_content = [line.strip() for line in news_content]
for update_date in image_update_dates:
update_date = datetime.datetime.strptime(
update_date, "## Image rotation update from %Y-%m-%d:"
)
for line_idx, line in enumerate(news_content):
if re.match(r".*\*\*[0-9]{4}-[0-9]{2}-[0-9]{2}\*\*.*", line):
news_date = line.split("**")[1]
news_date = datetime.datetime.strptime(news_date, "%Y-%m-%d")
if update_date > news_date or line_idx == len(news_content) - 1:
update_date = datetime.datetime.strftime(update_date, "%Y-%m-%d")
new_entry = [
f"**{update_date}** Image rotation update, details [here](https://docs.cloud.muni.cz/"
f"cloud/image-rotation/#image-rotation-update-from-{update_date})",
]
news_content = (
news_content[:line_idx] + new_entry + [""] + news_content[line_idx:]
if line_idx != len(news_content) - 1
else news_content + [""] + new_entry
)
break
with open(DOC_NEWS_FILE, "w", encoding="utf-8") as news_file:
news_file.write("\n".join(news_content))
if __name__ == "__main__":
IMAGE_UPDATE_DATES = get_image_update_log_dates()
if IMAGE_UPDATE_DATES:
generate_news(IMAGE_UPDATE_DATES)
baseURL = "http://localhost:1313/"
languageCode = "en-us"
title = "Metacentrum Cloud Documentation"
theme = "hugo-geekdoc"
pygmentsUseClasses = true
pygmentsCodeFences = true
disablePathToLower = true
geekdocMenuBundle = true
baseURL = "https://docs.cloud.muni.cz/"
languageCode = "en-us"
title = "Metacentrum Cloud Documentation"
theme = "hugo-geekdoc"
pygmentsUseClasses = true
pygmentsCodeFences = true
disablePathToLower = true
geekdocMenuBundle = true
---
title: "Introduction"
date: 2021-05-18T11:22:35+02:00
draft: false
disableToc: true
---
{{< hint danger >}}
**WARNING**
[User projects](/cloud/register/#personal-project) (generated for every user) are not meant to contain production machines.
If you use your personal project for long-term services, you have to ask for a [GROUP](/cloud/register/#group-project) project (even if you do not work in a group or you do not need any extra quotas).
{{</hint>}}
{{<hint info>}}
**Quick navigation:**
- [I want to request a group project.](/cloud/register/#group-project)
- [I want to request quota increase or additional flavor for existing project.](/cloud/register/#increase-quotas-for-existing-group-project)
- [I have a group project already and need to get machines up and running.](/cloud/quick-start/)
- [I need technical support or security contact.](https://cloud.muni.cz/contacts/)
{{</hint>}}
This guide aims to provide a walk-through for setting up a rudimentary
virtual infrastructure in MetaCentrum Cloud. It is a good jumping-off
point for most users.
MetaCentrum Cloud is the [IaaS cloud](https://en.wikipedia.org/wiki/Infrastructure_as_a_service) on top of [open-source OpenStack project](https://opendev.org/openstack).
Users may configure and use cloud resources for reaching individual (scientific) goals.
The most important cloud resources are:
* virtual machines
* virtual networking (VPNs, firewalls, routers)
* private and/or public IP addresses
* storage
* cloud load balancers
The left sidebar can be used for navigation throughout the documentation.
The whole guide can also be downloaded as PDFs for printing or later use.
__New users__ should head over to the [Get Access](cloud/register)
section and make sure they have an active user account and required
permissions to access the service.
__Beginners__ should start in the [Quick Start](cloud/quick-start)
a section that provides a step-by-step guide for starting the first
virtual machine instance.
__Advanced users__ should continue in the [Advanced Features](cloud/gui)
or [Command Line Interface](cloud/cli) sections, as these are
more suitable for complex use cases and exploration of available
features.
__Expert users__ with complex infrastructural or scientific use cases
should contact user support and request assistance specifically for
their use case.
__Frequently asked questions__ and corresponding answers can be found in
the [FAQ](cloud/faq) section. Please, consult this section before
contacting user support.
Bear in mind that this is not the complete documentation to OpenStack
but rather a quick guide that is supposed to help you with elementary
use of our infrastructure. If you need more information, please turn
to [the official documentation](https://docs.openstack.org/train/user/)
or contact user support and describe your use case.
Please visit the [Network](cloud/network) section to see how you should set up the network.
---
title: Cloud
---
---
title: "About metacentrum.cz cloud"
date: 2021-05-18T11:22:35+02:00
draft: false
weight: -100
GeekdocHidden: true
---
## Hardware
MetaCentrum Cloud consists of 17 computational clusters containing 277 hypervisors
with a sum of 8968 cores, 96 GPU cards, and 178 TB RAM. Special demand applications can utilize our clusters with local SSDs and GPU cards. OpenStack instances, object storage and image storage
can leverage more than 1.5 PTB of highly available data storage provided by the CEPH storage system.
## Software
MetaCentrum Cloud is built on top of OpenStack, which is a free open standard cloud computing platform
and one of the top 3 most active open source projects in the world. New OpenStack major versions are
released twice a year. OpenStack functionality is separated into more than 50 services.
## Application
More than 400 users are using the MetaCentrum Cloud platform and more than 130k VMs were started last year.
## MetaCentrum Cloud current release
OpenStack Train
## Deployed services
The following table contains a list of OpenStack services deployed in MetaCentrum Cloud. Services are separated
into two groups based on their stability and the level of support we are able to provide. All services in the production
group are well tested by our team and are covered by the support of cloud@metacentrum.cz. To be able to support
a variety of experimental cases we are planning to deploy several services as experimental, which can be useful
for testing purposes, but its functionality won't be covered by the support of cloud@metacentrum.cz.
| Service | Description | Type |
|-----------|------------------------|--------------|
| cinder | Block Storage service | production |
| glance | Image service | production |
| heat | Orchestration service | production |
| horizon | Dashboard | production |
| keystone | Identity service | production |
| neutron | Networking service | production |
| nova | Compute service | production |
| octavia | Load Balancing Service | experimental |
| placement | Placement service | production |
| swift/s3 | Object Storage service | production |
content/cloud/advanced-features/images/img_vis.png

70.2 KiB

content/cloud/advanced-features/images/network1.png

38.6 KiB

content/cloud/advanced-features/images/network2.png

28.7 KiB

content/cloud/advanced-features/images/network3.png

42.5 KiB

content/cloud/advanced-features/images/network4.png

26.9 KiB

content/cloud/advanced-features/images/network5.png

18 KiB

content/cloud/advanced-features/images/router1.png

26.1 KiB

content/cloud/advanced-features/images/router2.png

20.9 KiB