diff --git a/config-templates/countries.json b/config-templates/countries.json new file mode 100644 index 000000000..bda0b75fc --- /dev/null +++ b/config-templates/countries.json @@ -0,0 +1,1562 @@ +{ + "countries": { + "fji": { + "name": "Fiji", + "bbox": { + "minx": -180.0, + "miny": -21.9434274, + "maxx": 180.0, + "maxy": -12.2613866 + } + }, + "tza": { + "name": "Tanzania", + "bbox": { + "minx": 29.3269773, + "miny": -11.761254, + "maxx": 40.6584071, + "maxy": -0.9854812 + } + }, + "esh": { + "name": "W. Sahara", + "bbox": { + "minx": 15.5907052, + "miny": 60.3798713, + "maxx": 15.6024238, + "maxy": 60.3833937 + } + }, + "can": { + "name": "Canada", + "bbox": { + "minx": -141.00275, + "miny": 41.6765556, + "maxx": -52.3237664, + "maxy": 83.3362128 + } + }, + "usa": { + "name": "United States of America", + "bbox": { + "minx": -180.0, + "miny": -14.7608358, + "maxx": 180.0, + "maxy": 71.5889534 + } + }, + "kaz": { + "name": "Kazakhstan", + "bbox": { + "minx": 46.4932179, + "miny": 40.5686476, + "maxx": 87.3156336, + "maxy": 55.4421701 + } + }, + "uzb": { + "name": "Uzbekistan", + "bbox": { + "minx": 55.9985531, + "miny": 37.1816004, + "maxx": 73.2147728, + "maxy": 45.5906784 + } + }, + "png": { + "name": "Papua New Guinea", + "bbox": { + "minx": 140.8416553, + "miny": -11.8555739, + "maxx": 159.6934961, + "maxy": -0.5573576 + } + }, + "idn": { + "name": "Indonesia", + "bbox": { + "minx": 94.7717124, + "miny": -11.2085669, + "maxx": 141.0194444, + "maxy": 6.2744496 + } + }, + "arg": { + "name": "Argentina", + "bbox": { + "minx": -73.5605371, + "miny": -55.1925709, + "maxx": -53.6374515, + "maxy": -21.7808568 + } + }, + "chl": { + "name": "Chile", + "bbox": { + "minx": -109.6795789, + "miny": -56.725, + "maxx": -66.0753474, + "maxy": -17.4983832 + } + }, + "som": { + "name": "Somalia", + "bbox": { + "minx": 40.98918, + "miny": -1.8031969, + "maxx": 51.6177696, + "maxy": 12.1889121 + } + }, + "ken": { + "name": "Kenya", + "bbox": { + "minx": 33.9096888, + "miny": -4.8995204, + "maxx": 41.9067502, + "maxy": 4.62 + } + }, + "sdn": { + "name": "Sudan", + "bbox": { + "minx": 21.8143904, + "miny": 8.685278, + "maxx": 39.0576252, + "maxy": 22.224918 + } + }, + "tcd": { + "name": "Chad", + "bbox": { + "minx": 13.47348, + "miny": 7.44107, + "maxx": 24.0, + "maxy": 23.4507957 + } + }, + "hti": { + "name": "Haiti", + "bbox": { + "minx": -75.2384618, + "miny": 17.820859, + "maxx": -71.6217461, + "maxy": 20.2911852 + } + }, + "rus": { + "name": "Russia", + "bbox": { + "minx": -180.0, + "miny": 41.1850968, + "maxx": 180.0, + "maxy": 82.0586232 + } + }, + "bhs": { + "name": "Bahamas", + "bbox": { + "minx": -80.7001941, + "miny": 20.7059846, + "maxx": -72.4477521, + "maxy": 27.4734551 + } + }, + "flk": { + "name": "Falkland Is.", + "bbox": { + "minx": -3.0732108, + "miny": 56.4514328, + "maxx": -3.0731354, + "maxy": 56.4518577 + } + }, + "nor": { + "name": "Norway", + "bbox": { + "minx": -9.6846279, + "miny": -54.654, + "maxx": 34.6889114, + "maxy": 81.0280176 + } + }, + "grl": { + "name": "Greenland", + "bbox": { + "minx": -74.1250416, + "miny": 59.515387, + "maxx": -10.0288759, + "maxy": 83.875172 + } + }, + "atf": { + "name": "Fr. S. Antarctic Lands", + "bbox": { + "minx": 70.1274483, + "miny": -49.7098647, + "maxx": 70.1474483, + "maxy": -49.6898647 + } + }, + "tls": { + "name": "Timor-Leste", + "bbox": { + "minx": 124.0339863, + "miny": -9.6096854, + "maxx": 127.5433663, + "maxy": -8.1161123 + } + }, + "zaf": { + "name": "South Africa", + "bbox": { + "minx": 16.3335213, + "miny": -47.1788335, + "maxx": 38.2898954, + "maxy": -22.1250301 + } + }, + "lso": { + "name": "Lesotho", + "bbox": { + "minx": 27.0113763, + "miny": -30.6772773, + "maxx": 29.4557099, + "maxy": -28.5705652 + } + }, + "mex": { + "name": "Mexico", + "bbox": { + "minx": -118.599188, + "miny": 14.3886243, + "maxx": -86.493266, + "maxy": 32.7186679 + } + }, + "ury": { + "name": "Uruguay", + "bbox": { + "minx": -58.4947729, + "miny": -35.7824481, + "maxx": -53.0755833, + "maxy": -30.0853962 + } + }, + "bra": { + "name": "Brazil", + "bbox": { + "minx": -73.9830625, + "miny": -33.8689056, + "maxx": -28.6289646, + "maxy": 5.2695808 + } + }, + "bol": { + "name": "Bolivia", + "bbox": { + "minx": -69.6450073, + "miny": -22.8982742, + "maxx": -57.453, + "maxy": -9.6689438 + } + }, + "per": { + "name": "Peru", + "bbox": { + "minx": -84.6356535, + "miny": -20.1984472, + "maxx": -68.6519906, + "maxy": -0.0392818 + } + }, + "col": { + "name": "Colombia", + "bbox": { + "minx": -82.1243611, + "miny": -4.2294028, + "maxx": -66.8490386, + "maxy": 16.0495518 + } + }, + "pan": { + "name": "Panama", + "bbox": { + "minx": -83.0517245, + "miny": 7.0027171, + "maxx": -77.1585751, + "maxy": 9.8469028 + } + }, + "cri": { + "name": "Costa Rica", + "bbox": { + "minx": -87.2951397, + "miny": 5.2980534, + "maxx": -82.4299043, + "maxy": 11.2195684 + } + }, + "nic": { + "name": "Nicaragua", + "bbox": { + "minx": -87.8958171, + "miny": 10.7073945, + "maxx": -82.4767247, + "maxy": 15.0902778 + } + }, + "hnd": { + "name": "Honduras", + "bbox": { + "minx": -89.3568207, + "miny": 12.9808485, + "maxx": -82.18164, + "maxy": 17.619522 + } + }, + "slv": { + "name": "El Salvador", + "bbox": { + "minx": -90.2089183, + "miny": 12.9518017, + "maxx": -87.5971467, + "maxy": 14.4510488 + } + }, + "gtm": { + "name": "Guatemala", + "bbox": { + "minx": -92.3743889, + "miny": 13.5577935, + "maxx": -88.2134425, + "maxy": 17.8165947 + } + }, + "blz": { + "name": "Belize", + "bbox": { + "minx": -89.2275905, + "miny": 15.8857286, + "maxx": -87.2765017, + "maxy": 18.4959143 + } + }, + "ven": { + "name": "Venezuela", + "bbox": { + "minx": -73.3529632, + "miny": 0.6473964, + "maxx": -59.7707163, + "maxy": 15.9158431 + } + }, + "guy": { + "name": "Guyana", + "bbox": { + "minx": -61.3827449, + "miny": 1.1710017, + "maxx": -56.4689543, + "maxy": 8.6038842 + } + }, + "sur": { + "name": "Suriname", + "bbox": { + "minx": -58.0711851, + "miny": 1.8312802, + "maxx": -53.8601382, + "maxy": 6.2160842 + } + }, + "fra": { + "name": "France", + "bbox": { + "minx": -178.3873749, + "miny": -50.2187169, + "maxx": 172.3057152, + "maxy": 51.3055721 + } + }, + "ecu": { + "name": "Ecuador", + "bbox": { + "minx": -92.2072392, + "miny": -5.0159314, + "maxx": -75.192504, + "maxy": 1.8835964 + } + }, + "pri": { + "name": "Puerto Rico", + "bbox": { + "minx": -68.1109184, + "miny": 17.7306659, + "maxx": -65.1100908, + "maxy": 18.6663822 + } + }, + "jam": { + "name": "Jamaica", + "bbox": { + "minx": -78.5782366, + "miny": 16.5899443, + "maxx": -75.7541143, + "maxy": 18.7256394 + } + }, + "cub": { + "name": "Cuba", + "bbox": { + "minx": -85.1679702, + "miny": 19.6275294, + "maxx": -73.9190004, + "maxy": 23.4816972 + } + }, + "zwe": { + "name": "Zimbabwe", + "bbox": { + "minx": 25.2373, + "miny": -22.4241096, + "maxx": 33.0683501, + "maxy": -15.6097033 + } + }, + "bwa": { + "name": "Botswana", + "bbox": { + "minx": 19.9986486, + "miny": -26.9070073, + "maxx": 29.3738868, + "maxy": -17.778137 + } + }, + "nam": { + "name": "Namibia", + "bbox": { + "minx": 11.5280384, + "miny": -28.96945, + "maxx": 25.2617292, + "maxy": -16.9635105 + } + }, + "sen": { + "name": "Senegal", + "bbox": { + "minx": -17.7498686, + "miny": 12.2402664, + "maxx": -11.3459503, + "maxy": 16.6919712 + } + }, + "mli": { + "name": "Mali", + "bbox": { + "minx": -12.2402835, + "miny": 10.147811, + "maxx": 4.2673828, + "maxy": 25.001084 + } + }, + "mrt": { + "name": "Mauritania", + "bbox": { + "minx": -17.2380959, + "miny": 14.7209909, + "maxx": -4.8333344, + "maxy": 27.314942 + } + }, + "ben": { + "name": "Benin", + "bbox": { + "minx": 0.776667, + "miny": 6.0398696, + "maxx": 3.8451454, + "maxy": 12.4092028 + } + }, + "ner": { + "name": "Niger", + "bbox": { + "minx": 0.1689653, + "miny": 11.6936071, + "maxx": 15.996667, + "maxy": 23.517178 + } + }, + "nga": { + "name": "Nigeria", + "bbox": { + "minx": 2.676932, + "miny": 4.0690959, + "maxx": 14.678014, + "maxy": 13.885645 + } + }, + "cmr": { + "name": "Cameroon", + "bbox": { + "minx": 8.3822176, + "miny": 1.6517945, + "maxx": 16.1911011, + "maxy": 13.083333 + } + }, + "tgo": { + "name": "Togo", + "bbox": { + "minx": -0.1439746, + "miny": 5.926547, + "maxx": 1.8087257, + "maxy": 11.1395102 + } + }, + "gha": { + "name": "Ghana", + "bbox": { + "minx": -3.260786, + "miny": 4.5392525, + "maxx": 1.2732942, + "maxy": 11.1748562 + } + }, + "civ": { + "name": "C\u00f4te d'Ivoire", + "bbox": { + "minx": -8.6014675, + "miny": 4.1621205, + "maxx": -2.4948836, + "maxy": 10.740197 + } + }, + "gin": { + "name": "Guinea", + "bbox": { + "minx": -15.5680508, + "miny": 7.1906045, + "maxx": -7.6379222, + "maxy": 12.67563 + } + }, + "gnb": { + "name": "Guinea-Bissau", + "bbox": { + "minx": -16.897501, + "miny": 10.6514215, + "maxx": -13.6348777, + "maxy": 12.6862384 + } + }, + "lbr": { + "name": "Liberia", + "bbox": { + "minx": -11.6080764, + "miny": 4.1555907, + "maxx": -7.367323, + "maxy": 8.5519251 + } + }, + "sle": { + "name": "Sierra Leone", + "bbox": { + "minx": -13.5003389, + "miny": 6.755, + "maxx": -10.271683, + "maxy": 9.999973 + } + }, + "bfa": { + "name": "Burkina Faso", + "bbox": { + "minx": -5.513207, + "miny": 9.4104718, + "maxx": 2.4089717, + "maxy": 15.0840044 + } + }, + "cog": { + "name": "Congo", + "bbox": { + "minx": 12.039074, + "miny": -13.459035, + "maxx": 31.3056758, + "maxy": 5.3920026 + } + }, + "gab": { + "name": "Gabon", + "bbox": { + "minx": 8.5002246, + "miny": -4.1012261, + "maxx": 14.539444, + "maxy": 2.3192896 + } + }, + "zmb": { + "name": "Zambia", + "bbox": { + "minx": 21.9993509, + "miny": -18.0762145, + "maxx": 33.7095027, + "maxy": -8.2749338 + } + }, + "mwi": { + "name": "Malawi", + "bbox": { + "minx": 32.6718589, + "miny": -17.1296031, + "maxx": 35.9185731, + "maxy": -9.368301 + } + }, + "moz": { + "name": "Mozambique", + "bbox": { + "minx": 30.2121663, + "miny": -26.9209427, + "maxx": 41.0545908, + "maxy": -10.3252149 + } + }, + "swz": { + "name": "eSwatini", + "bbox": { + "minx": 30.7908, + "miny": -27.3175201, + "maxx": 32.1349834, + "maxy": -25.71876 + } + }, + "ago": { + "name": "Angola", + "bbox": { + "minx": 11.4609793, + "miny": -18.0393809, + "maxx": 24.0876359, + "maxy": -4.3458006 + } + }, + "bdi": { + "name": "Burundi", + "bbox": { + "minx": 29.000716, + "miny": -4.4693155, + "maxx": 30.8498462, + "maxy": -2.3096796 + } + }, + "isr": { + "name": "Israel", + "bbox": { + "minx": 34.2674994, + "miny": 29.4533796, + "maxx": 35.8950234, + "maxy": 33.3356317 + } + }, + "lbn": { + "name": "Lebanon", + "bbox": { + "minx": 34.8825667, + "miny": 33.0550325, + "maxx": 36.625, + "maxy": 34.6921448 + } + }, + "mdg": { + "name": "Madagascar", + "bbox": { + "minx": 42.9680076, + "miny": -25.784021, + "maxx": 50.6727307, + "maxy": -11.732889 + } + }, + "pse": { + "name": "Palestine", + "bbox": { + "minx": 34.0546906, + "miny": 31.2201289, + "maxx": 35.5403583, + "maxy": 32.5489422 + } + }, + "gmb": { + "name": "Gambia", + "bbox": { + "minx": -17.0223778, + "miny": 13.0558333, + "maxx": -13.797778, + "maxy": 13.8253137 + } + }, + "tun": { + "name": "Tunisia", + "bbox": { + "minx": 7.5219807, + "miny": 30.229061, + "maxx": 11.8801133, + "maxy": 37.7612052 + } + }, + "dza": { + "name": "Algeria", + "bbox": { + "minx": -8.668908, + "miny": 18.968147, + "maxx": 11.997337, + "maxy": 37.2962055 + } + }, + "jor": { + "name": "Jordan", + "bbox": { + "minx": 34.8844372, + "miny": 29.183401, + "maxx": 39.3012981, + "maxy": 33.3750617 + } + }, + "are": { + "name": "United Arab Emirates", + "bbox": { + "minx": 51.4160714, + "miny": 22.6316214, + "maxx": 56.6024458, + "maxy": 26.1517219 + } + }, + "qat": { + "name": "Qatar", + "bbox": { + "minx": 50.5675, + "miny": 24.4707534, + "maxx": 52.638011, + "maxy": 26.434565 + } + }, + "kwt": { + "name": "Kuwait", + "bbox": { + "minx": 46.5526837, + "miny": 28.5243622, + "maxx": 49.0046809, + "maxy": 30.1038082 + } + }, + "irq": { + "name": "Iraq", + "bbox": { + "minx": 38.7936719, + "miny": 29.0585661, + "maxx": 49.1067706, + "maxy": 37.3806687 + } + }, + "omn": { + "name": "Oman", + "bbox": { + "minx": 52.0000004, + "miny": 16.4649608, + "maxx": 60.054577, + "maxy": 26.7026737 + } + }, + "vut": { + "name": "Vanuatu", + "bbox": { + "minx": 166.3355255, + "miny": -20.4627425, + "maxx": 170.449982, + "maxy": -12.8713777 + } + }, + "khm": { + "name": "Cambodia", + "bbox": { + "minx": 102.3338282, + "miny": 9.4110961, + "maxx": 107.6276788, + "maxy": 14.6904224 + } + }, + "tha": { + "name": "Thailand", + "bbox": { + "minx": 97.3438072, + "miny": 5.612851, + "maxx": 105.636812, + "maxy": 20.4648337 + } + }, + "lao": { + "name": "Laos", + "bbox": { + "minx": 100.0843247, + "miny": 13.9096752, + "maxx": 107.6349989, + "maxy": 22.5086717 + } + }, + "mmr": { + "name": "Myanmar", + "bbox": { + "minx": 92.1729181, + "miny": 9.526084, + "maxx": 101.1700796, + "maxy": 28.547835 + } + }, + "vnm": { + "name": "Vietnam", + "bbox": { + "minx": 102.1438643, + "miny": 7.6920852, + "maxx": 114.8572578, + "maxy": 23.3926918 + } + }, + "prk": { + "name": "North Korea", + "bbox": { + "minx": 124.092355, + "miny": 37.5833302, + "maxx": 130.8861177, + "maxy": 43.0089642 + } + }, + "kor": { + "name": "South Korea", + "bbox": { + "minx": 124.3727348, + "miny": 32.9104556, + "maxx": 132.1467806, + "maxy": 38.61772 + } + }, + "mng": { + "name": "Mongolia", + "bbox": { + "minx": 87.7345852, + "miny": 41.5800276, + "maxx": 119.9322079, + "maxy": 52.1496 + } + }, + "ind": { + "name": "India", + "bbox": { + "minx": 67.9544415, + "miny": 6.5531169, + "maxx": 97.395561, + "maxy": 35.6745457 + } + }, + "bgd": { + "name": "Bangladesh", + "bbox": { + "minx": 88.007915, + "miny": 20.3679092, + "maxx": 92.6802967, + "maxy": 26.6382534 + } + }, + "btn": { + "name": "Bhutan", + "bbox": { + "minx": 88.7464856, + "miny": 26.7016859, + "maxx": 92.1252321, + "maxy": 28.2474194 + } + }, + "npl": { + "name": "Nepal", + "bbox": { + "minx": 80.0570812, + "miny": 26.3477581, + "maxx": 88.2015257, + "maxy": 30.471487 + } + }, + "pak": { + "name": "Pakistan", + "bbox": { + "minx": 60.872855, + "miny": 23.4341977, + "maxx": 77.1203914, + "maxy": 37.084107 + } + }, + "afg": { + "name": "Afghanistan", + "bbox": { + "minx": 60.5176034, + "miny": 29.3772926, + "maxx": 74.889862, + "maxy": 38.4910682 + } + }, + "tjk": { + "name": "Tajikistan", + "bbox": { + "minx": 67.3332775, + "miny": 36.6711153, + "maxx": 75.1539563, + "maxy": 41.0450935 + } + }, + "kgz": { + "name": "Kyrgyzstan", + "bbox": { + "minx": 69.2649523, + "miny": 39.1727382, + "maxx": 80.2295793, + "maxy": 43.2669041 + } + }, + "tkm": { + "name": "Turkmenistan", + "bbox": { + "minx": 52.2643526, + "miny": 35.129093, + "maxx": 66.6903725, + "maxy": 42.7996686 + } + }, + "irn": { + "name": "Iran", + "bbox": { + "minx": 44.0318908, + "miny": 24.8353084, + "maxx": 63.3332704, + "maxy": 39.7824624 + } + }, + "syr": { + "name": "Syria", + "bbox": { + "minx": 35.4714427, + "miny": 32.311354, + "maxx": 42.3745894, + "maxy": 37.3186563 + } + }, + "arm": { + "name": "Armenia", + "bbox": { + "minx": 43.4471395, + "miny": 38.8404775, + "maxx": 46.6333087, + "maxy": 41.3016463 + } + }, + "swe": { + "name": "Sweden", + "bbox": { + "minx": 10.5935025, + "miny": 55.1370957, + "maxx": 24.1776819, + "maxy": 69.0599735 + } + }, + "blr": { + "name": "Belarus", + "bbox": { + "minx": 23.1783313, + "miny": 51.2626864, + "maxx": 32.7627809, + "maxy": 56.1722484 + } + }, + "ukr": { + "name": "Ukraine", + "bbox": { + "minx": 22.137059, + "miny": 44.184598, + "maxx": 40.2275801, + "maxy": 52.3797464 + } + }, + "pol": { + "name": "Poland", + "bbox": { + "minx": 14.0696389, + "miny": 49.0020468, + "maxx": 24.145783, + "maxy": 55.03605 + } + }, + "aut": { + "name": "Austria", + "bbox": { + "minx": 9.5307487, + "miny": 46.3722987, + "maxx": 17.1607728, + "maxy": 49.0205249 + } + }, + "hun": { + "name": "Hungary", + "bbox": { + "minx": 16.1138866, + "miny": 45.737128, + "maxx": 22.8977094, + "maxy": 48.585257 + } + }, + "mda": { + "name": "Moldova", + "bbox": { + "minx": 26.6164054, + "miny": 45.4672099, + "maxx": 30.1637143, + "maxy": 48.4920527 + } + }, + "rou": { + "name": "Romania", + "bbox": { + "minx": 20.2619955, + "miny": 43.618682, + "maxx": 30.0454257, + "maxy": 48.2654738 + } + }, + "ltu": { + "name": "Lithuania", + "bbox": { + "minx": 20.6557167, + "miny": 53.8967893, + "maxx": 26.8355198, + "maxy": 56.4504213 + } + }, + "lva": { + "name": "Latvia", + "bbox": { + "minx": 20.6009852, + "miny": 55.6746505, + "maxx": 28.2414904, + "maxy": 58.0855688 + } + }, + "est": { + "name": "Estonia", + "bbox": { + "minx": 21.3826069, + "miny": 57.5093328, + "maxx": 28.2100175, + "maxy": 59.9383333 + } + }, + "deu": { + "name": "Germany", + "bbox": { + "minx": 5.8663153, + "miny": 47.2701114, + "maxx": 15.0419309, + "maxy": 55.099161 + } + }, + "bgr": { + "name": "Bulgaria", + "bbox": { + "minx": 22.3571459, + "miny": 41.2353678, + "maxx": 28.8875409, + "maxy": 44.2155388 + } + }, + "grc": { + "name": "Greece", + "bbox": { + "minx": 19.1127535, + "miny": 34.7188863, + "maxx": 29.68381, + "maxy": 41.7488889 + } + }, + "tur": { + "name": "Turkey", + "bbox": { + "minx": 25.5656305, + "miny": 35.8059015, + "maxx": 44.8176638, + "maxy": 42.297 + } + }, + "alb": { + "name": "Albania", + "bbox": { + "minx": 19.0009866, + "miny": 39.640394, + "maxx": 21.0574335, + "maxy": 42.6610848 + } + }, + "hrv": { + "name": "Croatia", + "bbox": { + "minx": 13.2104814, + "miny": 42.1765993, + "maxx": 19.4472713, + "maxy": 46.555029 + } + }, + "che": { + "name": "Switzerland", + "bbox": { + "minx": 5.9559113, + "miny": 45.8179716, + "maxx": 10.4922941, + "maxy": 47.8084597 + } + }, + "lux": { + "name": "Luxembourg", + "bbox": { + "minx": 5.7357006, + "miny": 49.4478587, + "maxx": 6.5312481, + "maxy": 50.1827726 + } + }, + "bel": { + "name": "Belgium", + "bbox": { + "minx": 2.3889137, + "miny": 49.4969821, + "maxx": 6.408097, + "maxy": 51.550781 + } + }, + "nld": { + "name": "Netherlands", + "bbox": { + "minx": -68.6255319, + "miny": 11.825, + "maxx": 7.2274985, + "maxy": 53.744395 + } + }, + "prt": { + "name": "Portugal", + "bbox": { + "minx": -31.5575303, + "miny": 29.828247, + "maxx": -6.1891593, + "maxy": 42.1543112 + } + }, + "esp": { + "name": "Spain", + "bbox": { + "minx": -18.3936845, + "miny": 27.4335426, + "maxx": 4.5918885, + "maxy": 43.9933088 + } + }, + "irl": { + "name": "Ireland", + "bbox": { + "minx": -11.0133788, + "miny": 51.222, + "maxx": -5.6582363, + "maxy": 55.636 + } + }, + "ncl": { + "name": "New Caledonia", + "bbox": { + "minx": 157.9847541, + "miny": -23.2217509, + "maxx": 172.3057152, + "maxy": -17.6868616 + } + }, + "slb": { + "name": "Solomon Is.", + "bbox": { + "minx": -83.4848851, + "miny": 35.8292625, + "maxx": -82.8448851, + "maxy": 36.4692625 + } + }, + "nzl": { + "name": "New Zealand", + "bbox": { + "minx": -179.059153, + "miny": -52.8213687, + "maxx": 179.3643594, + "maxy": -29.0303303 + } + }, + "aus": { + "name": "Australia", + "bbox": { + "minx": 72.2461932, + "miny": -55.3228175, + "maxx": 168.2261259, + "maxy": -9.0880125 + } + }, + "lka": { + "name": "Sri Lanka", + "bbox": { + "minx": 79.3959205, + "miny": 5.719, + "maxx": 82.0810141, + "maxy": 10.035 + } + }, + "chn": { + "name": "China", + "bbox": { + "minx": 73.4997347, + "miny": 8.6650385, + "maxx": 134.7754563, + "maxy": 53.5608154 + } + }, + "twn": { + "name": "Taiwan", + "bbox": { + "minx": 114.2857874, + "miny": 10.3267657, + "maxx": 122.3283, + "maxy": 26.4372222 + } + }, + "ita": { + "name": "Italy", + "bbox": { + "minx": 6.6272658, + "miny": 35.2889616, + "maxx": 18.7844746, + "maxy": 47.0921462 + } + }, + "dnk": { + "name": "Denmark", + "bbox": { + "minx": 7.7153255, + "miny": 54.4516667, + "maxx": 15.5530641, + "maxy": 57.9524297 + } + }, + "gbr": { + "name": "United Kingdom", + "bbox": { + "minx": -14.015517, + "miny": 49.674, + "maxx": 2.0919117, + "maxy": 61.061 + } + }, + "isl": { + "name": "Iceland", + "bbox": { + "minx": -25.0135069, + "miny": 63.0859177, + "maxx": -12.8046162, + "maxy": 67.353 + } + }, + "aze": { + "name": "Azerbaijan", + "bbox": { + "minx": 44.7633701, + "miny": 38.3929551, + "maxx": 51.1765554, + "maxy": 41.9646768 + } + }, + "geo": { + "name": "Georgia", + "bbox": { + "minx": 39.8844803, + "miny": 41.0551284, + "maxx": 46.7365373, + "maxy": 43.5864294 + } + }, + "phl": { + "name": "Philippines", + "bbox": { + "minx": 114.1036921, + "miny": 4.3833333, + "maxx": 126.803083, + "maxy": 21.321928 + } + }, + "mys": { + "name": "Malaysia", + "bbox": { + "minx": 98.7365109, + "miny": 0.8538205, + "maxx": 119.4699634, + "maxy": 8.3801468 + } + }, + "brn": { + "name": "Brunei", + "bbox": { + "minx": 113.017925, + "miny": 4.002508, + "maxx": 115.3635623, + "maxy": 6.546584 + } + }, + "svn": { + "name": "Slovenia", + "bbox": { + "minx": 13.3754696, + "miny": 45.4214242, + "maxx": 16.5968135, + "maxy": 46.8766816 + } + }, + "fin": { + "name": "Finland", + "bbox": { + "minx": 19.0832, + "miny": 59.4541578, + "maxx": 31.5867071, + "maxy": 70.0922939 + } + }, + "svk": { + "name": "Slovakia", + "bbox": { + "minx": 16.8331891, + "miny": 47.7311798, + "maxx": 22.56571, + "maxy": 49.6138162 + } + }, + "cze": { + "name": "Czechia", + "bbox": { + "minx": 12.0905752, + "miny": 48.5518081, + "maxx": 18.8592538, + "maxy": 51.0556945 + } + }, + "eri": { + "name": "Eritrea", + "bbox": { + "minx": 36.4333653, + "miny": 12.3548219, + "maxx": 43.3001714, + "maxy": 18.0709917 + } + }, + "jpn": { + "name": "Japan", + "bbox": { + "minx": 122.7141754, + "miny": 20.2145811, + "maxx": 154.205541, + "maxy": 45.7112046 + } + }, + "pry": { + "name": "Paraguay", + "bbox": { + "minx": -62.6406685, + "miny": -27.6063935, + "maxx": -54.258, + "maxy": -19.2876472 + } + }, + "yem": { + "name": "Yemen", + "bbox": { + "minx": 41.60825, + "miny": 11.9084802, + "maxx": 54.7389375, + "maxy": 19.0 + } + }, + "sau": { + "name": "Saudi Arabia", + "bbox": { + "minx": 34.4571718, + "miny": 16.29, + "maxx": 55.6666851, + "maxy": 32.1543377 + } + }, + "ata": { + "name": "Antarctica", + "bbox": { + "minx": -24.6850688, + "miny": -104.4063075, + "maxx": 25.3149312, + "maxy": -54.4063075 + } + }, + "cyn": { + "name": "N. Cyprus", + "bbox": { + "minx": 32.4871506, + "miny": 35.0030286, + "maxx": 34.8553182, + "maxy": 35.913252 + } + }, + "cyp": { + "name": "Cyprus", + "bbox": { + "minx": 32.0227581, + "miny": 34.4383706, + "maxx": 34.8553182, + "maxy": 35.913252 + } + }, + "mar": { + "name": "Morocco", + "bbox": { + "minx": -17.2448353, + "miny": 21.333462, + "maxx": -0.998429, + "maxy": 36.0021392 + } + }, + "egy": { + "name": "Egypt", + "bbox": { + "minx": 24.6499112, + "miny": 21.9936736, + "maxx": 37.1153517, + "maxy": 31.8330854 + } + }, + "lby": { + "name": "Libya", + "bbox": { + "minx": 9.391081, + "miny": 19.4999907, + "maxx": 25.3770629, + "maxy": 33.3545898 + } + }, + "eth": { + "name": "Ethiopia", + "bbox": { + "minx": 32.9975838, + "miny": 3.397448, + "maxx": 47.9823797, + "maxy": 14.8943383 + } + }, + "dji": { + "name": "Djibouti", + "bbox": { + "minx": 41.7713139, + "miny": 10.9149547, + "maxx": 43.6579046, + "maxy": 12.7923081 + } + }, + "sol": { + "name": "Somaliland", + "bbox": { + "minx": 42.708703, + "miny": 7.9998309, + "maxx": 49.0800591, + "maxy": 11.7160828 + } + }, + "uga": { + "name": "Uganda", + "bbox": { + "minx": 29.573433, + "miny": -1.4823179, + "maxx": 35.000308, + "maxy": 4.2340766 + } + }, + "rwa": { + "name": "Rwanda", + "bbox": { + "minx": 28.861696, + "miny": -2.8397581, + "maxx": 30.8990738, + "maxy": -1.0474083 + } + }, + "bih": { + "name": "Bosnia and Herz.", + "bbox": { + "minx": 18.4251913, + "miny": 43.8592358, + "maxx": 18.4255335, + "maxy": 43.8596085 + } + }, + "mkd": { + "name": "North Macedonia", + "bbox": { + "minx": 20.4529023, + "miny": 40.8536596, + "maxx": 23.034051, + "maxy": 42.3739044 + } + }, + "srb": { + "name": "Serbia", + "bbox": { + "minx": 18.8149945, + "miny": 42.2314466, + "maxx": 23.006309, + "maxy": 46.1902839 + } + }, + "mne": { + "name": "Montenegro", + "bbox": { + "minx": 18.4195781, + "miny": 41.6849866, + "maxx": 20.3529276, + "maxy": 43.5585061 + } + }, + "-99": { + "name": "Kosovo", + "bbox": { + "minx": 20.0142844, + "miny": 41.8576408, + "maxx": 21.7899366, + "maxy": 43.2733306 + } + }, + "tto": { + "name": "Trinidad and Tobago", + "bbox": { + "minx": -62.083056, + "miny": 9.8732106, + "maxx": -60.2895848, + "maxy": 11.5628372 + } + }, + "ssd": { + "name": "S. Sudan", + "bbox": { + "minx": 23.447778, + "miny": 3.48898, + "maxx": 35.948997, + "maxy": 12.236389 + } + } + }, + "_comment": "Generated on 2023-08-31 from geopandas, OpenStreetMap and Nominatim" +} diff --git a/config-templates/csv2bufr_mappings.json b/config-templates/csv2bufr_mappings.json new file mode 100644 index 000000000..46ecec2c2 --- /dev/null +++ b/config-templates/csv2bufr_mappings.json @@ -0,0 +1,57 @@ +{ + "inputShortDelayedDescriptorReplicationFactor": [], + "inputDelayedDescriptorReplicationFactor": [0,0], + "inputExtendedDelayedDescriptorReplicationFactor": [], + "wigos_station_identifier": "data:WIGOS_ID", + "number_header_rows": 1, + "column_names_row": 1, + "delimiter": ",", + "quoting": "QUOTE_NONE", + "header":[ + {"eccodes_key": "edition", "value": "const:4"}, + {"eccodes_key": "masterTableNumber", "value": "const:0"}, + {"eccodes_key": "bufrHeaderCentre", "value": "const:0"}, + {"eccodes_key": "bufrHeaderSubCentre", "value": "const:0"}, + {"eccodes_key": "updateSequenceNumber", "value": "const:0"}, + {"eccodes_key": "dataCategory", "value": "const:0"}, + {"eccodes_key": "internationalDataSubCategory", "value": "const:6"}, + {"eccodes_key": "masterTablesVersionNumber", "value": "const:30"}, + {"eccodes_key": "numberOfSubsets", "value": "const:1"}, + {"eccodes_key": "observedData", "value": "const:1"}, + {"eccodes_key": "compressedData", "value": "const:0"}, + {"eccodes_key": "typicalYear", "value":"data:YEAR"}, + {"eccodes_key": "typicalMonth", "value":"data:MONTH"}, + {"eccodes_key": "typicalDay", "value":"data:DAY OF MONTH"}, + {"eccodes_key": "typicalHour", "value":"data:HOUR"}, + {"eccodes_key": "typicalMinute", "value":"data:MINUTE"}, + {"eccodes_key": "unexpandedDescriptors", "value": "array:301150,307080"} + ], + "data": [ + {"eccodes_key": "#1#wigosIdentifierSeries", "value":"data:_wsi_series"}, + {"eccodes_key": "#1#wigosIssuerOfIdentifier", "value":"data:_wsi_issuer"}, + {"eccodes_key": "#1#wigosIssueNumber", "value":"data:_wsi_issue_number"}, + {"eccodes_key": "#1#wigosLocalIdentifierCharacter", "value":"data:_wsi_local"}, + {"eccodes_key": "#1#year", "value":"data:YEAR", "valid_min": "const:2000", "valid_max": "const:2100"}, + {"eccodes_key": "#1#month", "value":"data:MONTH", "valid_min": "const:1", "valid_max": "const:12"}, + {"eccodes_key": "#1#day", "value":"data:DAY OF MONTH", "valid_min": "const:1", "valid_max": "const:31"}, + {"eccodes_key": "#1#hour", "value":"data:HOUR", "valid_min": "const:0", "valid_max": "const:23"}, + {"eccodes_key": "#1#minute", "value":"data:MINUTE", "valid_min": "const:0", "valid_max": "const:59"}, + {"eccodes_key": "#1#latitude", "value":"data:LATITUDE", "valid_min": "const:-90", "valid_max": "const:90"}, + {"eccodes_key": "#1#longitude", "value":"data:LONGITUDE", "valid_min": "const:-180", "valid_max": "const:180"}, + {"eccodes_key": "#1#heightOfStationGroundAboveMeanSeaLevel", "value":"data:STATION HEIGHT (m)"}, + {"eccodes_key": "#1#heightOfBarometerAboveMeanSeaLevel", "value":"data:BP HEIGHT (m)"}, + {"eccodes_key": "#1#nonCoordinatePressure", "value":"data:BARO PRESSURE(hPa)"}, + {"eccodes_key": "#1#airTemperature", "value":"data:AIR TEMP(C)", "offset": "const:273.15", "scale": "const:0"}, + {"eccodes_key": "#1#dewpointTemperature", "value":"data:DEW POINT(C)", "offset": "const:273.15", "scale": "const:0"}, + {"eccodes_key": "#1#relativeHumidity", "value":"data:REL HUMID(%)"}, + {"eccodes_key": "#1#windSpeed", "value":"data:WIND SPD(m/s)"}, + {"eccodes_key": "#1#windDirection", "value":"data:WIND DIR(deg)"}, + {"eccodes_key": "#2#timePeriod", "value":"const:-1"}, + {"eccodes_key": "#1#totalSunshine", "value":"data:HOURS SUN(hrs)"}, + {"eccodes_key": "#1#totalPrecipitationOrTotalWaterEquivalent", "value":"data:PRECIP(mm)"}, + {"eccodes_key": "#1#maximumWindGustSpeed", "value":"data:GUST(m/s)"}, + {"eccodes_key": "#1#maximumWindGustDirection", "value": "data:GUSTDIR(deg)"}, + {"eccodes_key": "#14#timePeriod", "value":"const:-1"}, + {"eccodes_key": "#1#globalSolarRadiationIntegratedOverPeriodSpecified", "value":"data:SOLAR RAD(WH/m2)", "offset": "const:0", "scale": "const:3.56"} + ] +} \ No newline at end of file diff --git a/config-templates/data-mappings.yml.tmpl b/config-templates/data-mappings.yml.tmpl new file mode 100644 index 000000000..64a2bc672 --- /dev/null +++ b/config-templates/data-mappings.yml.tmpl @@ -0,0 +1,47 @@ +data: + $COUNTRY_CODE.$CENTRE_ID.data.core.weather.surface-based-observations.synop: + plugins: + txt: + - plugin: wis2box.data.synop2bufr.ObservationDataSYNOP2BUFR + notify: true + buckets: + - $${WIS2BOX_STORAGE_INCOMING} + file-pattern: '^.*-(\d{4})(\d{2}).*\.txt$$' + csv: + - plugin: wis2box.data.csv2bufr.ObservationDataCSV2BUFR + template: /data/wis2box/csv2bufr_mappings.json + notify: true + buckets: + - $${WIS2BOX_STORAGE_INCOMING} + file-pattern: '^.*\.csv$$' + bin: + - plugin: wis2box.data.bufr4.ObservationDataBUFR + notify: true + buckets: + - $${WIS2BOX_STORAGE_INCOMING} + file-pattern: '^.*\.bin$$' + bufr: + - plugin: wis2box.data.bufr4.ObservationDataBUFR + notify: true + buckets: + - $${WIS2BOX_STORAGE_INCOMING} + file-pattern: '^.*\.bufr$$' + bufr4: + - plugin: wis2box.data.bufr2geojson.ObservationDataBUFR2GeoJSON + buckets: + - $${WIS2BOX_STORAGE_PUBLIC} + file-pattern: '^WIGOS_(\d-\d+-\d+-\w+)_.*\.bufr4$$' + COUNTRY_CODE.CENTRE_ID.data.core.weather.surface-based-observations.temp: + plugins: + bin: + - plugin: wis2box.data.bufr4.ObservationDataBUFR + notify: true + buckets: + - $${WIS2BOX_STORAGE_INCOMING} + file-pattern: '^.*\.bin$$' + bufr: + - plugin: wis2box.data.bufr4.ObservationDataBUFR + notify: true + buckets: + - $${WIS2BOX_STORAGE_INCOMING} + file-pattern: '^.*\.bufr$$' diff --git a/config-templates/metadata-synop.yml.tmpl b/config-templates/metadata-synop.yml.tmpl new file mode 100644 index 000000000..ce0d1a28f --- /dev/null +++ b/config-templates/metadata-synop.yml.tmpl @@ -0,0 +1,63 @@ +wis2box: + retention: P30D + topic_hierarchy: $COUNTRY_CODE.$CENTRE_ID.data.core.weather.surface-based-observations.synop + country: $COUNTRY_CODE + centre_id: $CENTRE_ID + +mcf: + version: 1.0 + +metadata: + identifier: urn:x-wmo:md:$COUNTRY_CODE:$CENTRE_ID:surface-based-observations.synop + language: en + charset: utf8 + hierarchylevel: dataset + +identification: + language: en + charset: utf8 + title: Surface weather observations from $CENTRE_NAME + abstract: Surface weather observations from $CENTRE_NAME + dates: + creation: $CREATION_DATE + publication: $PUBLICATION_DATE + keywords: + default: + keywords: + - upper-air weather + - observations + wmo: + keywords: + - weatherObservations + keywords_type: theme + vocabulary: + name: WMO Category Code + url: https://github.com/wmo-im/wcmp-codelists/blob/main/codelists/WMO_CategoryCode.csv + extents: + spatial: + - bbox: [$BOUNDING_BOX] + crs: 4326 + temporal: + - begin: BEGIN_DATE + end: null + resolution: P1H + wmo_data_policy: core + +contact: + pointOfContact: &contact_poc + organization: $CENTRE_NAME + url: NA + individualname: NA + positionname: NA + phone: NA + fax: NA + address: NA + city: NA + administrativearea: NA + postalcode: NA + country: $COUNTRY_NAME + email: $WIS2BOX_EMAIL + hoursofservice: NA + contactinstructions: email + + distributor: *contact_poc diff --git a/config-templates/metadata-temp.yml.tmpl b/config-templates/metadata-temp.yml.tmpl new file mode 100644 index 000000000..ab06448e6 --- /dev/null +++ b/config-templates/metadata-temp.yml.tmpl @@ -0,0 +1,63 @@ +wis2box: + retention: P30D + topic_hierarchy: $COUNTRY_CODE.$CENTRE_ID.data.core.weather.surface-based-observations.temp + country: $COUNTRY_CODE + centre_id: $CENTRE_ID + +mcf: + version: 1.0 + +metadata: + identifier: urn:x-wmo:md:$COUNTRY_CODE:$CENTRE_ID:surface-based-observations.temp + language: en + charset: utf8 + hierarchylevel: dataset + +identification: + language: en + charset: utf8 + title: Upper-air weather observations from $CENTRE_NAME + abstract: Upper-air weather observations from $CENTRE_NAME + dates: + creation: $CREATION_DATE + publication: $PUBLICATION_DATE + keywords: + default: + keywords: + - upper-air weather + - observations + wmo: + keywords: + - weatherObservations + keywords_type: theme + vocabulary: + name: WMO Category Code + url: https://github.com/wmo-im/wcmp-codelists/blob/main/codelists/WMO_CategoryCode.csv + extents: + spatial: + - bbox: [$BOUNDING_BOX] + crs: 4326 + temporal: + - begin: BEGIN_DATE + end: null + resolution: P12H + wmo_data_policy: core + +contact: + pointOfContact: &contact_poc + organization: $CENTRE_NAME + url: NA + individualname: NA + positionname: NA + phone: NA + fax: NA + address: NA + city: NA + administrativearea: NA + postalcode: NA + country: $COUNTRY_NAME + email: $WIS2BOX_EMAIL + hoursofservice: NA + contactinstructions: email + + distributor: *contact_poc diff --git a/config-templates/station_list_example.csv b/config-templates/station_list_example.csv new file mode 100644 index 000000000..2b3ac6094 --- /dev/null +++ b/config-templates/station_list_example.csv @@ -0,0 +1,4 @@ +station_name,wigos_station_identifier,traditional_station_identifier,facility_type,latitude,longitude,elevation,territory_name,wmo_region +EXAMPLE1-SURFACE,0-454-0-EXAMPLE,,Land (fixed),-14.98333,34.96666,618,Malawi,I +EXAMPLE2-SURFACE,0-20000-0-12345,12345,Land (fixed),41.56361,14.65500,793,Italy,VI +EXAMPLE3-UPPERAIR,0-52-0-5432,54321,Air (fixed),13.08585,-59.48701,56.6,Barbados,IV \ No newline at end of file diff --git a/docs/source/user/setup.rst b/docs/source/user/setup.rst index d910d49c2..cf876c60f 100644 --- a/docs/source/user/setup.rst +++ b/docs/source/user/setup.rst @@ -3,7 +3,8 @@ Installation and configuration ============================== -This section summarizes the steps required to install a wis2box instance and setup your own datasets using example configurations. +This section summarizes the steps required to install a wis2box instance and setup your own datasets using initial configuration files +provided by using the ``wis2box-create-config.py`` script. Ensure you have Docker, Docker Compose and Python installed on your host, as detailed in :ref:`getting-started`. @@ -15,148 +16,28 @@ and download the ``wis2box-setup-1.0b4.zip`` file from the Assets section. .. code-block:: bash - wget https://github.com/wmo-im/wis2box/releases/download/1.0b4/wis2box-setup-1.0b4.zip - unzip wis2box-setup-1.0b4.zip - cd wis2box-1.0b4 + wget https://github.com/wmo-im/wis2box/releases/download/1.0b4/wis2box-setup-1.0b5.zip + unzip wis2box-setup-1.0b5.zip + cd wis2box-1.0b5 -Environment variables ---------------------- - -wis2box uses environment variables from ``dev.env`` to its containers on startup. -An example file is provided in ``examples/config/wis2box.extended.env``. -Copy this file to your working directory, and update it to suit your needs. - -.. code-block:: bash - - cp examples/config/wis2box.env dev.env - -.. note:: - Please ensure you set ``WIS2BOX_BROKER_PASSWORD`` and ``WIS2BOX_STORAGE_PASSWORD`` to your own unique values. - - You will use these passwords to connect to your broker and MinIO storage to help you debug your wis2box services. - - Do not share these passwords with external parties. - -.. note:: - - You must map ``WIS2BOX_HOST_DATADIR`` to the absolute path of a directory on your host machine. This path will be mapped to ``/data/wis2box`` inside the **wis2box-management** container. - To enable external data sharing you must set ``WIS2BOX_URL`` to the URL pointing to where your host is exposed on the public network. - -For example you can create a ``wis2box-data`` directory in your home directory as follows: - -.. code-block:: bash - - mkdir /home//wis2box-data - -And you can edit ``dev.env`` to match the location - -.. code-block:: bash - - WIS2BOX_HOST_DATADIR=/home//wis2box-data - -Data mappings -------------- - -wis2box configuration requires a data mappings file, which defines the plugins used to process your data. -Example mapping files are included in the release archive: - -* ``synop-bufr-mappings.yml``, input is binary data (BUFR) defined by a ``.bufr`` extension -* ``synop-csv-mappings.yml``, input is comma-separated-values defined by a ``.csv`` extension -* ``synop-synop-mappings.yml``, input is SYNOP defined with a ``.txt`` extension - -For example, if your incoming data contains ``.bufr4`` files containing synoptic observations, you can copy the following example: - -.. code-block:: bash +Create initial configuration files +---------------------------------- - cp examples/config/synop-bufr-mappings.yml ~/wis2box-data/data-mappings.yml - -.. note:: - - The file should be called ``data-mappings.yml`` and should be placed in the directory you defined as ``WIS2BOX_HOST_DATADIR``. - -Edit ``~/wis2box-data/data-mappings.yml``: - - * Replace ``country`` with your corresponding ISO 3166 alpha-3 country code in lowercase - * Replace ``centre_id`` with the string identifying the centre running your wis2node in lowercase, alphanumeric characters - -If you need to define multiple datasets, you can add multiple entries in your ``data-mappings.yml``. For example: +Run the following command to create the initial configuration files for your wis2box: .. code-block:: bash - data: - ita.italy_wmo_demo.data.core.weather.surface-based-observations.synop: - plugins: - bufr: - - plugin: wis2box.data.bufr4.ObservationDataBUFR - notify: true - buckets: - - ${WIS2BOX_STORAGE_INCOMING} - file-pattern: '*' - bufr4: - - plugin: wis2box.data.bufr2geojson.ObservationDataBUFR2GeoJSON - buckets: - - ${WIS2BOX_STORAGE_PUBLIC} - file-pattern: '^WIGOS_(\d-\d+-\d+-\w+)_.*\.bufr4$' - ita.italy_wmo_demo.data.core.weather.surface-based-observations.temp: - plugins: - bufr: - - plugin: wis2box.data.bufr4.ObservationDataBUFR - notify: true - buckets: - - ${WIS2BOX_STORAGE_INCOMING} - file-pattern: '*' - bufr4: - - plugin: wis2box.data.bufr2geojson.ObservationDataBUFR2GeoJSON - buckets: - - ${WIS2BOX_STORAGE_PUBLIC} - file-pattern: '^WIGOS_(\d-\d+-\d+-\w+)_.*\.bufr4$' - -In this case the data mappings configuration has specified 2 datasets (SYNOP, and TEMP). - -You can also combine input for the same dataset provided in different formats. -For example, if you would like to process input data that is provided both as SYNOP and binary data: - -.. code-block:: bash - - data: - ita.italy_wmo_demo.data.core.weather.surface-based-observations.synop: - plugins: - bufr: - - plugin: wis2box.data.bufr4.ObservationDataBUFR - notify: true - buckets: - - ${WIS2BOX_STORAGE_INCOMING} - file-pattern: '*' - csv: - - plugin: wis2box.data.csv2bufr.ObservationDataCSV2BUFR - template: synop_bufr.json - notify: true - file-pattern: '*' - bufr4: - - plugin: wis2box.data.bufr2geojson.ObservationDataBUFR2GeoJSON - buckets: - - ${WIS2BOX_STORAGE_PUBLIC} - file-pattern: '^WIGOS_(\d-\d+-\d+-\w+)_.*\.bufr4$' - -.. note:: - - The dataset identifier is used to define the topic hierarchy for your data (see `WIS2 topic hierarchy`_). The top 3 levels of the WIS2 topic hierarchy (``origin/a/wis2``) are automatically included by wis2box when publishing your data. - - * dataset: ita.italy_wmo_demo.data.core.weather.surface-based-observations.synop - * topic-hierarchy: origin/a/wis2/ita/italy_wmo_demo/data/core/weather/surface-based-observations/synop + python3 wis2box-create-config.py .. note:: - - In these examples, files in the ``wis2box-incoming`` storage bucket are processed to produce ``.bufr4`` stored in the ``wis2box-public`` storage bucket, using either the ``bufr4.ObservationDataBUFR`` or the ``wis2box.data.csv2bufr.ObservationDataCSV2BUFR`` plugins. - - Files in the ``wis2box-public`` storage bucket are converted to GeoJSON and stored in the wis2box API backend using the ``wis2box.data.bufr2geojson.ObservationDataBUFR2GeoJSON`` plugin. - You can provide your own plugins as needed; for more information (see :ref:`extending-wis2box`). + The ``wis2box-create-config.py`` program will ask for a directory to store the configuration files. + This directory will be mapped to ``/data/wis2box`` **inside** the wis2box-management container. -Station metadata list ---------------------- +Adding your own station data +---------------------------- wis2box requires information about the stations for which you will be sharing data. @@ -171,6 +52,9 @@ You can copy this file to ``metadata/station/station_list.csv`` in your $WIS2BOX And edit ``~/wis2box-data/metadata/station/station_list.csv`` to include the data for your stations. +The 'wis2box-create-config.py' script will create the file ``metadata/station/station_list.csv`` file in the directory + you specified for your configuration files. You will have to edit this file to add your own station data using the examples provided. + .. note:: The ``station_list.csv`` requires column names ``station_name`` and the ``wigos_station_identifier`` (WSI) with which the station is registered in `OSCAR`_. Optionally, you can provide a ``traditional_station_identifier (TSI)`` column. @@ -193,23 +77,17 @@ Discovery metadata Discovery metadata provides the data description needed for users to discover your data when searching the WIS2 Global Discovery Catalogue. -Updated discovery metadata records are shared globally through the MQTT endpoint defined in your wis2box. - -Discovery metadata records can be defined using the YAML syntax shared via ``WIS2BOX_HOST_DATADIR``. - -An example is provided in ``surface-weather-observations.yml``. Each dataset requires its own discovery metadata configuration file. - -You can copy the file ``surface-weather-observations.yml`` to the directory defined for ``WIS2BOX_HOST_DATADIR``: - -.. code-block:: bash +The discovery metadata is provided in the form of a YAML file. - cp examples/config/surface-weather-observations.yml ~/wis2box-data/metadata/station +If you used the ``python3 wis2box-create-config.py`` command to initialize your wis2box, you will find two initial the discovery metadata files in +the directory you specified for your configuration files, under the ``metadata/discovery/`` directory: + +* ``metadata-synop.yml``: contains the discovery metadata for the ``synop`` dataset +* ``metadata-temp.yml``: contains the discovery metadata for the ``temp`` dataset -And update it to provide the correct discovery metadata for your dataset: +Please review the content of these files and edit them as needed. -* replace ``[country].[centre_id].data.core.weather.surface-based-observations.synop`` with the topic as previously used in ``$WIS2BOX_HOST_DATADIR/data-mappings.yml`` -* text provided in ``identification.title`` and ``identification.abstract`` will be displayed in the wis2box user interface -* provide a valid geographic bounding box in ``identification.extents.spatial.bbox`` +You can also add additional discovery metadata files for any other datasets you wish to publish. Starting wis2box ---------------- @@ -267,7 +145,8 @@ Which should display the following: Refer to the :ref:`troubleshooting` section if this is not the case. -You should now be able to view collections on the wis2box API by visiting ``http://localhost/oapi/collections`` in a web browser, which should appear as follows: +You should now be able to view collections on the wis2box API by visiting the URL you specified during the configuration step, + and adding ``/oapi/collections`` to the URL. .. image:: ../_static/wis2box-api-initial.png :width: 800 @@ -291,49 +170,49 @@ Login to the wis2box-management container python3 wis2box-ctl.py login -.. note:: - - ``$WIS2BOX_DATADIR`` is the location that ``$WIS2BOX_HOST_DATADIR`` binds to **inside** the container. - This allows wis2box to access the configuration files from **inside** the wis2box-management container. - By default, ``WIS2BOX_DATADIR`` points to ``/data/wis2box`` **inside** the wis2box-management container. +The first step is to add your collection to the wis2box API, using the discovery metadata file you created above. -The first step is add the new dataset as defined by the YAML file for your discovery metadata record defined previously, using the following command: +For example to add the data collection defined in ``metadata/discovery/metadata-synop.yml`` in the directory you specified for your configuration files: .. code-block:: bash - wis2box data add-collection ${WIS2BOX_DATADIR}/surface-weather-observations.yml - + wis2box data add-collection /data/wis2box/metadata/discovery/metadata-synop.yml .. note:: - If you see an error like ``ValueError: No plugins for XXX defined in data mappings``, exit the wis2box-container and edit the ``data-mappings.yml`` file in the directory defined by ``WIS2BOX_HOST_DATADIR`` + If you see an error like ``ValueError: No plugins for XXX defined in data mappings``, exit the wis2box-management container and edit the ``data-mappings.yml`` file + in your wis2box configuration directory. -You can view the collection you just added, by re-visiting ``http://localhost/oapi/collections`` in a web browser. +You can view the collection you just added, by re-visiting ``/oapi/collections`` in a web browser. .. image:: ../_static/wis2box-api-added-collection.png :width: 800 :alt: wis2box API collections list with added collection +Repeat this step for any other collections you wish to add, such as the ``temp`` dataset. + The second step is to publish discovery metadata and cache its content in the wis2box API: .. code-block:: bash - wis2box metadata discovery publish ${WIS2BOX_DATADIR}/surface-weather-observations.yml + wis2box metadata discovery publish /data/wis2box/metadata/discovery/metadata-synop.yml This command publishes an MQTT message with information about your dataset to the WIS2 Global Discovery Catalogue. Repeat this command whenever you have to provide updated metadata about your dataset. -You can review the discovery metadata just cached through the new link in ``http://localhost/oapi/collections``: +You can review the discovery metadata just cached through the new link at ``/oapi/collections``: .. image:: ../_static/wis2box-api-discovery-metadata.png :width: 800 :alt: wis2box API collections list with added discovery metadata +Repeat this step for any other discovery metadata you wish to publish, such as the ``temp`` dataset. + The final step is to publish your station information to the wis2box API from the station metadata list you prepared: .. code-block:: bash wis2box metadata station publish-collection -You can review the stations you just cached through the new link in ``http://localhost/oapi/collections``: +You can review the stations you just cached through the new link at ``/oapi/collections``: .. image:: ../_static/wis2box-api-stations.png :width: 800 diff --git a/wis2box-create-config.py b/wis2box-create-config.py new file mode 100644 index 000000000..5fbaf65e8 --- /dev/null +++ b/wis2box-create-config.py @@ -0,0 +1,601 @@ +############################################################################### +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +############################################################################### + +import datetime +import json +import os +from pathlib import Path +import random +import string +from string import Template +from typing import Tuple + + +def get_bounding_box(country_code: str) -> Tuple[str, str]: + """ + provide the initial bounding box for the wis2box + using the country's 3-letter ISO code + using the data from config-templates/bounding_box_lookup.json + + use bounding box for the whole world if no value is found in + the config-templates/bounding_box_lookup.json file + + :param country_code: `str` 3-letter ISO code for the country + + :returns: `tuple` of (country_name, bbox) + """ + + country_name = 'NA' + bounding_box = [-180, -90, 180, 90] + + print(f"Getting bounding box for '{country_code}'.") + + # get the path to the data + data_path = Path(__file__).parent / 'config-templates' / 'countries.json' + + # open the file + with data_path.open() as fh: + # load the data + data = json.load(fh) + # get the bounding box for the country + if country_code in data['countries'] and 'bbox' in data['countries'][country_code]: # noqa + country_name = data['countries'][country_code]["name"] + bbox = data['countries'][country_code]["bbox"] + if not {'minx', 'miny', 'maxx', 'maxy'} <= bbox.keys(): + print(f"Bounding box for '{country_code}' is invalid.") + print("Using global bounding box.") + else: + minx = bbox['minx'] + miny = bbox['miny'] + maxx = bbox['maxx'] + maxy = bbox['maxy'] + # create bounding box as a CSV of four numbers + bounding_box = f"{minx},{miny},{maxx},{maxy}" + else: + print(f"No bounding box found for '{country_code}'.") + print("Using the bounding box for the whole world.") + + # ask the user to accept the bounding box or to enter a new one + print(f"bounding box: {bounding_box}.") + print("Do you want to use this bounding box? (y/n/exit)") + answer = input() + + while answer not in ['y', 'exit']: + print("Please enter the bounding box as a comma-separated list of four numbers:") # noqa + print("The first two numbers are the coordinates of the lower left corner of the bounding box.") # noqa + print("The last two numbers are the coordinates of the upper right corner of the bounding box.") # noqa + print("For example: 5.5,47.2,15.5,55.2") + bounding_box = input() + print(f"bounding box: {bounding_box}.") + print("Do you want to use this bounding box? (y/n/exit)") + answer = input() + + if answer == "exit": + exit() + + return country_name, bounding_box + + +def get_country_and_centre_id() -> Tuple[str, str]: + """ + Asks the user for the 3-letter ISO country-code + and a string identifying the centre hosting the wis2box. + + :returns: `tuple` of (country_code, centre_id) + """ + + answer = "" + + while answer != "y": + if answer == "exit": + exit() + + print("Please enter your 3-letter ISO country code:") + country_code = input() + + # check that the input is a 3-letter string + # if not repeat the question + while len(country_code) != 3: + print("The country code must be a 3-letter string.") + print("Please enter your 3-letter ISO country code:") + country_code = input() + + # make sure the country code is lowercase + country_code = country_code.lower() + + print("Please enter the centre-id for your wis2box:") + centre_id = str(input()).lower() + + # check that the input is valid + # if not repeat the question + while any([x in centre_id for x in ['#', '+', ' ']]) or len(centre_id) < 3: # noqa + print("The centre-id cannot contain spaces or the '+' or '#' characters, and must be at least 3 characters long.") # noqa + print("Please enter the string identifying the centre hosting the wis2box:") # noqa + centre_id = str(input()).lower() + + # ask the user to confirm their choice and give them the option to change it # noqa + # and give them the option to exit the script + print("The country-code will be set to:") + print(f" {country_code}") + print("The centre-id will be set to:") + print(f" {centre_id}") + print("Is this correct? (y/n/exit)") + answer = input() + + return (country_code, centre_id) + + +def get_password(password_name: str) -> str: + """ + asks the user to enter a password or to use a randomly generated password + + :param password_name: `str` of password entered + + :returns: `str` of password to be used + """ + + password = None + + answer = "" + while answer not in ['y', 'n']: + if answer == "exit": + exit() + + print(f"Do you want to use a randomly generated password for {password_name} (y/n/exit)") # noqa + answer = input() + + if answer == "y": + password = ''.join(random.choice(string.ascii_letters + string.digits) for i in range(8)) # noqa + print(f"{password_name}={password}") + + while answer != "y": + if answer == "exit": + exit() + + print("Please enter the password to be used for the WIS2BOX_STORAGE_PASSWORD:") # noqa + password = input() + + # check if the password is at least 8 characters long + # if not repeat the question + while len(password) < 8: + print("The password must be at least 8 characters long.") + print(f"Please enter the password to be used for the {password_name}:") # noqa + password = input() + + print(f"{password_name}={password}") + print("Is this correct? (y/n/exit)") + answer = input() + + return f"{password_name}={password}\n" + + +def get_wis2box_url() -> str: + """ + asks the user to enter the URL of the wis2box + + :returns: `str` of wis2box URL + """ + + wis2box_url = None + answer = "" + + while answer != "y": + if answer == "exit": + exit() + + # ask for the WIS2BOX_URL, use http://localhost as the default + print("Please enter the URL of the wis2box:") + print(" When running the wis2box locally, the default is http://localhost") # noqa + print(" To enable remote access, please enter the public IP address or domain name of the server hosting the wis2box.") # noqa + + # check if the URL starts with http:// or https:// + # if not, ask the user to enter the URL again + wis2box_url = "" + wis2box_url = input() + + while not wis2box_url.startswith(("http://", "https://")): + print("The URL must start with http:// or https://") + print("Please enter the URL of the wis2box:") + wis2box_url = input() + + # ask the user to confirm their choice and give them the option to change it # noqa + print("The URL of the wis2box will be set to:") + print(f" {wis2box_url}") + print("Is this correct? (y/n/exit)") + answer = input() + + return wis2box_url + + +def create_dev_env(config_dir: str) -> None: + """ + creates the dev.env file in the config_dir + + :param config_dir: `str` of path to the config directory + + :returns: None + """ + + dev_env = Path("dev.env") + + with dev_env.open("w") as fh: + fh.write(f"WIS2BOX_HOST_DATADIR={config_dir}\n") + fh.write("\n") + wis2box_url = get_wis2box_url() + fh.write(f"WIS2BOX_URL={wis2box_url}\n") + fh.write(f"WIS2BOX_API_URL={wis2box_url}/oapi\n") + fh.write("\n") + # use the default username wis2box for WIS2BOX_STORAGE_USERNAME + fh.write("WIS2BOX_STORAGE_USERNAME=wis2box\n") + # get password for WIS2BOX_STORAGE_PASSWORD and write it to dev.env + fh.write(get_password("WIS2BOX_STORAGE_PASSWORD")) + fh.write("\n") + # write default port and host for WIS2BOX_BROKER + fh.write("WIS2BOX_BROKER_PORT=1883\n") + fh.write("WIS2BOX_BROKER_HOST=mosquitto\n") + # use the default username wis2box for WIS2BOX_BROKER_USERNAME + fh.write("WIS2BOX_BROKER_USERNAME=wis2box\n") + # get password for WIS2BOX_BROKER_PASSWORD and write it to dev.env + fh.write(get_password("WIS2BOX_BROKER_PASSWORD")) + fh.write("\n") + # update WIS2BOX_PUBLIC_BROKER settings after updating broker defaults + fh.write("# update WIS2BOX_PUBLIC_BROKER settings after updating broker defaults\n") # noqa + fh.write("WIS2BOX_BROKER_PUBLIC=mqtt://${WIS2BOX_BROKER_USERNAME}:${WIS2BOX_BROKER_PASSWORD}@mosquitto:1883\n") # noqa + # update minio settings after updating storage and broker defaults + fh.write("\n") + fh.write("# update minio settings after updating storage and broker defaults\n") # noqa + fh.write("MINIO_ROOT_USER=${WIS2BOX_STORAGE_USERNAME}\n") + fh.write("MINIO_ROOT_PASSWORD=${WIS2BOX_STORAGE_PASSWORD}\n") + fh.write("MINIO_NOTIFY_MQTT_USERNAME_WIS2BOX=${WIS2BOX_BROKER_USERNAME}\n") # noqa + fh.write("MINIO_NOTIFY_MQTT_PASSWORD_WIS2BOX=${WIS2BOX_BROKER_PASSWORD}\n") # noqa + fh.write("MINIO_NOTIFY_MQTT_BROKER_WIS2BOX=tcp://${WIS2BOX_BROKER_HOST}:${WIS2BOX_BROKER_PORT}\n") # noqa + + print("*" * 80) + print("The file dev.env has been created in the current directory.") + print("*" * 80) + + +def create_config_dir() -> str: + """ + Creates the directory config_dir + + If the directory already exists, asks the user if they want to overwrite + the existing files + + :returns: `str` of path to directory where configuration files + are to be stored + """ + + config_dir = "" + answer = "n" + + while answer != "y": + if answer == "exit": + exit() + + print("Please enter the directory on the host where wis2box-configuration-files are to be stored:") # noqa + config_dir = input() + + if config_dir == "": + print("The directory cannot be empty.") + continue + + print("Configuration-files will be stored in the following directory:") # noqa + print(f" {config_dir}") + print("Is this correct? (y/n/exit)") + answer = input() + + config_dir = Path(config_dir) + + # check if the directory exists + if config_dir.is_dir(): + # if it exists warn the user + # tell them that the directory needs to be remove to continue + print("WARNING:") + print(f"The directory {config_dir} already exists.") + print("Please remove the directory to restart the configuration process.") # noqa + exit() + else: + # if it does not exist, create it + config_dir.mkdir() + # check if the directory was created + if not config_dir.is_dir(): + print("ERROR:") + print(f"The directory {config_dir} could not be created.") + print("Please check the path and your permissions.") + exit() + print(f"The directory {config_dir} has been created.") + + return config_dir + + +def create_datamappings_file(config_dir: str, country_code: str, + centre_id: str) -> None: + """ + creates the data mappings file in the directory config_dir + + :param config_dir: `str` of path to directory where configuration files + are to be stored + :param country_code: `str` of the country code of the wis2box + :param centre_id: `str` of the centre id of the wis2box + + :returns: None + """ + + template_file = Path("config-templates/data-mappings.yml.tmpl") + new_config_file = Path(config_dir) / "data-mappings.yml" + csv2bufr_mappings_template_file = Path("config-templates/csv2bufr_mappings.json") # noqa + csv2bufr_mappings_file = Path(config_dir) / 'csv2bufr_mappings.json' + + template_vars = { + 'COUNTRY_CODE': country_code, + 'CENTRE_ID': centre_id + } + with template_file.open() as fh: + config_file = Template(fh.read()) + result = config_file.substitute(template_vars) + with new_config_file.open("w") as fh2: + fh2.write(result) + + # also add mappings.json from config-templates to config_dir + with csv2bufr_mappings_template_file.open() as fh: + mappings_file = fh.read() + with csv2bufr_mappings_file.open("w") as fh2: + fh2.write(mappings_file) + + print("*" * 80) + print("Initial data_mappings.yml and csv2bufr_mappings.json have been created") # noqa + print("Please review the files and update as needed.") + print("*" * 80) + + +def create_metadata_file(config_dir: str, country_code: str, country_name, + centre_id: str, centre_name: str, wis2box_email: str, + bounding_box: str, template: str) -> str: + """ + creates the metadata file in the directory config_dir + + :param config_dir: `str` of the path to the directory where the configuration files are to be stored # noqa + :param country_code: `str` of the country code of the wis2box + :param country_name: `str` of the country name of the wis2box + :param centre_id: `str` of the centre id of the wis2box + :param centre_name: `str` of centre name of the wis2box + :param wis2box_email: `str` of centre email + :param bounding_box: `str` of CSV of bounding box + :param template: `str` of synop or temp + + :returns: `str` of the path to the metadata file + """ + + # get current date as a string + current_date = datetime.datetime.now().strftime("%Y-%m-%d") + + config_dir = Path(config_dir) + discovery_metadata_dir = config_dir / 'metadata' / 'discovery' + + # create directory for discovery metadata if it does not exist + if not discovery_metadata_dir.exists(): + discovery_metadata_dir.mkdir(parents=True) + + new_config_file = discovery_metadata_dir / f'metadata-{template}.yml' + template_file = Path('config-templates') / f'metadata-{template}.yml.tmpl' # noqa + + template_vars = { + 'PUBLICATION_DATE': current_date, + 'START_DATE': current_date, + 'CREATION_DATE': current_date, + 'COUNTRY_CODE': country_code, + 'COUNTRY_NAME': country_name, + 'CENTRE_ID': centre_id, + 'CENTRE_NAME': centre_name, + 'WIS2BOX_EMAIL': wis2box_email, + 'BOUNDING_BOX': bounding_box + } + + with template_file.open() as fh: + config_file = Template(fh.read()) + result = config_file.substitute(template_vars) + with new_config_file.open("w") as fh2: + fh2.write(result) + print(f"Created new metadata file: {new_config_file}") + + return new_config_file.name + + +def create_metadata_files(config_dir: str, country_code: str, + centre_id: str) -> None: + """ + creates the metadata files in the directory config_dir + + :config_dir: `str` of path to directory where configuration files + are to be stored # noqa + :country_code: `str` of country code of the country hosting the wis2box + :centre_id: `str` of centre id of the organization hosting the wis2box + + :returns: None + """ + + # ask for the email address of the wis2box administrator + answer = "" + wis2box_email = "" + + while answer != "y": + if answer == "exit": + exit() + + print("Please enter the email address of the wis2box administrator:") + wis2box_email = input() + print("The email address of the wis2box administrator will be set to:") # noqa + print(f" {wis2box_email}") + print("Is this correct? (y/n/exit)") + answer = input() + + # ask for the name of the centre + answer = "" + + while answer != "y": + if answer == "exit": + exit() + print("Please enter the name of your organization:") + centre_name = input() + print("Your organization name will be set to:") + print(f" {centre_name}") + print("Is this correct? (y/n/exit)") + answer = input() + + # get an initial bounding box for the country + country_name, bounding_box = get_bounding_box(country_code) + + create_metadata_file( + config_dir, + country_code, + country_name, + centre_id, + centre_name, + wis2box_email, + bounding_box, + template="synop" + ) + create_metadata_file( + config_dir, + country_code, + country_name, + centre_id, + centre_name, + wis2box_email, + bounding_box, + template="temp" + ) + + print("*" * 80) + print(f"Initial metadata files created in directory {config_dir}.") # noqa + print("Please review the files and edit where necessary.") + print("*" * 80) + + +def create_station_list(config_dir: str) -> None: + """ + creates the station list file in the directory config_dir + + :param config_dir: `str` of path to directory where configuration files + are to be stored + + :returns: None + """ + + station_metadata_dir = Path(config_dir) / 'metadata' / 'station' + station_list_template_file = Path('config-templates') / 'station_list_example.csv' # noqa + + # create directory for station metadata if it does not exist + if not station_metadata_dir.exists(): + station_metadata_dir.mkdir() + + # create station list file + new_config_file = station_metadata_dir / "station_list.csv" + + with station_list_template_file.open() as fh: + config_file = fh.read() + with new_config_file.open("w") as fh2: + fh2.write(config_file) + + print("*" * 80) + print(f"Created the file {new_config_file}.") + print("Please add your stations to this file.") + print("*" * 80) + + +def get_config_dir() -> str: + """ + reads the value of WIS2BOX_HOST_DATADIR from dev.env + + returns: `str` of path to directory where configuration files + are to be stored + """ + + config_dir = None + + with Path("dev.env").open() as fh: + lines = fh.readlines() + + for line in lines: + if "WIS2BOX_HOST_DATADIR" in line: + config_dir = line.split("=")[1].strip() + + if not config_dir: + print("WARNING:") + print("The file dev.env does not contain the variable WIS2BOX_HOST_DATADIR.") # noqa + print("Please edit the file and add the variable WIS2BOX_HOST_DATADIR.") # noqa + print("Or remove dev.env and run 'python3 wis2box-create-config.py' again.") # noqa + exit() + + return config_dir + + +def main(): + """ + mainline function + + creates the configuration files for the wis2box + """ + + config_dir = None + dev_env = Path("dev.env") + + # check if dev.env exists + # if it does, read the value for WIS2BOX_HOST_DATADIR + # or give the user the option to recreate dev.env + if dev_env.is_file(): + print("The file dev.env already exists in the current directory.") + print("Do you want to recreate dev.env? (y/n/exit)") + answer = input() + + if answer == "y": + os.remove("dev.env") + elif answer == "exit": + exit() + else: + config_dir = get_config_dir() + + # if config_dir is not defined + if not config_dir: + config_dir = create_config_dir() + + # if dev.env does not exist + # create it and write config_dir as the value for WIS2BOX_HOST_DATADIR to dev.env # noqa + if not dev_env.is_file(): + create_dev_env(config_dir) + + country_code, centre_id = get_country_and_centre_id() + + print("*" * 80) + print("Creating initial configuration for surface and upper-air data.") + print("*" * 80) + + create_metadata_files(config_dir, country_code, centre_id) + create_datamappings_file(config_dir, country_code, centre_id) + create_station_list(config_dir) + + print("The configuration is complete.") + exit() + + +if __name__ == "__main__": + main() diff --git a/wis2box-ctl.py b/wis2box-ctl.py index 0c85a6a6c..d7254eaf8 100755 --- a/wis2box-ctl.py +++ b/wis2box-ctl.py @@ -162,6 +162,9 @@ def make(args) -> None: run(args, split( f'{DOCKER_COMPOSE_COMMAND} {docker_compose_args} build {containers}')) elif args.command in ["up", "start", "start-dev"]: + if not os.path.exists('dev.env'): + print("ERROR: dev.env file does not exist. Please create one manually or by running `python3 wis2box-create-config.py`") + exit(1) run(args, split( 'docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions > /dev/null 2>&1')) run(args, split( diff --git a/wis2box-management/wis2box/env.py b/wis2box-management/wis2box/env.py index f7167e34a..b6e8dfadd 100644 --- a/wis2box-management/wis2box/env.py +++ b/wis2box-management/wis2box/env.py @@ -33,7 +33,6 @@ try: DATADIR = Path(os.environ.get('WIS2BOX_DATADIR')) - DATADIR_CONFIG = DATADIR / 'config' except (OSError, TypeError): msg = 'Configuration filepaths do not exist!' LOGGER.error(msg) @@ -138,9 +137,6 @@ def create(ctx, verbosity): # TODO: abstract into wis2box.storage.fs.FileSystemStorage click.echo(f'Creating baseline directory structure in {DATADIR}') DATADIR.mkdir(parents=True, exist_ok=True) - # DATADIR_ARCHIVE.mkdir(parents=True, exist_ok=True) - # DATADIR_CONFIG.mkdir(parents=True, exist_ok=True) - (DATADIR / 'cache').mkdir(parents=True, exist_ok=True) (DATADIR / 'metadata' / 'discovery').mkdir(parents=True, exist_ok=True) (DATADIR / 'metadata' / 'station').mkdir(parents=True, exist_ok=True)