diff --git a/Application.cfc b/Application.cfc index 4397b48..b7e2b46 100644 --- a/Application.cfc +++ b/Application.cfc @@ -26,6 +26,7 @@ + @@ -127,20 +128,20 @@ Вообще не следует ничего блокировать на время сетевого взаимодействия Нижеследующая, на первый взгляд, странная конструкция ровно для этого придумана ---> - onRequest:check for cert started #(getTickCount()-request.startTickCount)# + - Obtain IDP Certificate (onRequest) + - onRequest:check for cert finished #(getTickCount()-request.startTickCount)# + @@ -152,24 +153,26 @@ - + - сессия есть + - сессии нет + @@ -183,9 +186,9 @@ может быть, KeyCloak так защищается от циклических редиректов Не очень понятно, как предотвратить повторный запрос (можно, конечно, использовать сессию, но странно) */ - writeOutput(getTickCount()-request.startTickCount); + //writeOutput(getTickCount()-request.startTickCount); if(structKeyExists(url, "code")) { //обрабатываем редирект от IDP *** наличие поля code в URL введет нас в заблуждение, но эvar = data, label =то только без валидной сессии - dump(var = url.code, label = "URL.code"); + //dump(var = url.code, label = "URL.code"); // Request access token from idp with the // authorization code that we got via the URL //aFormFields = []; @@ -196,13 +199,13 @@ resp = idp.makeAccessTokenRequest(url.code/*, aFormFields*/); writeOutput("idp.makeAccessTokenRequest Done"); writeOutput(getTickCount()-request.startTickCount); - dump(resp); + //dump(resp); data = deserializeJson(resp.content); //writedump(data); // Print full response from idp - dump(var = data, label = "makeAccessTokenRequest - Response from idp"); + //dump(var = data, label = "makeAccessTokenRequest - Response from idp"); - echo('Refresh token #data.refresh_token#'); + //echo('Refresh token #data.refresh_token#'); session.auth.expires_in = data.expires_in; session.auth.refresh_expires_in = data.refresh_expires_in; diff --git a/inc/functions.cfm b/inc/functions.cfm index 6959b87..baf398d 100644 --- a/inc/functions.cfm +++ b/inc/functions.cfm @@ -49,10 +49,12 @@ function timeFmt(date, sFormat = 'HH:MM'){ } request.timeFmt = timeFmt; +////////////////////////////////////////////////////// function usrAuthenticated() { - return request.usr_id GT 0 AND NOT (request.usr_id EQ request.ANONYMOUS_USR_ID); + return structKeyExists(request, "auth"); } request.usrAuthenticated = usrAuthenticated; +///////////////////////////////////////////////////// function filterOn(filter) { return (isStruct(filter) AND NOT structIsEmpty(filter)); diff --git a/inc/menu.cfm b/inc/menu.cfm index 5b13946..e6938c1 100644 --- a/inc/menu.cfm +++ b/inc/menu.cfm @@ -10,49 +10,7 @@ \ No newline at end of file diff --git a/index.cfm b/index.cfm index 5398d53..ee2c01e 100644 --- a/index.cfm +++ b/index.cfm @@ -5,3 +5,4 @@ По истечении установленного времени (скажем, половины срока жизни токена) идем к IDP за рефрешем Сертификат открытого ключа можно каждый раз получать от IDP. Запрос к IDP идет только для освежения сессии, а не на каждый запрос. Логаут на IDP не проверяется при каждом запросе. + diff --git a/layout/attribute.cfm b/layout/attribute.cfm new file mode 100644 index 0000000..89bd22e --- /dev/null +++ b/layout/attribute.cfm @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/layout/column_head.cfm b/layout/column_head.cfm new file mode 100644 index 0000000..480b8a5 --- /dev/null +++ b/layout/column_head.cfm @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ATTRIBUTES.title# + \ No newline at end of file diff --git a/layout/detail_buttons.cfm b/layout/detail_buttons.cfm new file mode 100644 index 0000000..36a9912 --- /dev/null +++ b/layout/detail_buttons.cfm @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/layout/detail_line.cfm b/layout/detail_line.cfm new file mode 100644 index 0000000..7381cbb --- /dev/null +++ b/layout/detail_line.cfm @@ -0,0 +1,10 @@ + + + +
+
#ATTRIBUTES.title#
+
\ No newline at end of file diff --git a/layout/filter_buttons.cfm b/layout/filter_buttons.cfm new file mode 100644 index 0000000..5626fea --- /dev/null +++ b/layout/filter_buttons.cfm @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/layout/filter_link.cfm b/layout/filter_link.cfm new file mode 100644 index 0000000..b1f51a1 --- /dev/null +++ b/layout/filter_link.cfm @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + #request.i18("Фильтр...","Filter")##request.i18("Фильтр","Filter")# + (#request.i18("снять","reset")#) + \ No newline at end of file diff --git a/layout/grid_head.cfm b/layout/grid_head.cfm new file mode 100644 index 0000000..2d3d599 --- /dev/null +++ b/layout/grid_head.cfm @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/layout/grid_summary.cfm b/layout/grid_summary.cfm new file mode 100644 index 0000000..cc56219 --- /dev/null +++ b/layout/grid_summary.cfm @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
 
+
+ + + Выбрано #ATTRIBUTES.recordCount# + + из #ATTRIBUTES.totalCount# + + + + + + + + + + +
+
+ #paginator.links# +
+
+
+
+ + + + +
+ #paginator.links# +
+
+
+
+ + diff --git a/layout/json.cfm b/layout/json.cfm new file mode 100644 index 0000000..47ebf3b --- /dev/null +++ b/layout/json.cfm @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + ---> + + + + + + + + + + + + + [{"#listGetAt(#columnsOut#,i)#":"#qry[listGetAt(#columnsIn#,i)]#",},] + ---> + + + + + + + + + + + + + + + //copy fields to structure, renaming fields, this preserves data type + + + + + + + + + + + + + + + + + + + +#query2json(ATTRIBUTES.qRead,ATTRIBUTES.convertSnakeToCamel)# + \ No newline at end of file diff --git a/layout/language_switch.cfm b/layout/language_switch.cfm new file mode 100644 index 0000000..6533051 --- /dev/null +++ b/layout/language_switch.cfm @@ -0,0 +1,9 @@ + + +   +   +   + style="font-weight:bold;">Ru + style="font-weight:bold;"
>En + + \ No newline at end of file diff --git a/layout/page.cfm b/layout/page.cfm new file mode 100644 index 0000000..5b43472 --- /dev/null +++ b/layout/page.cfm @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +---> + + + + + + + + + + + + +<cfoutput>#pageTitle#</cfoutput> + + + + + + + + ---> + + + + + + + + + + +
+
+ + +
+ + + +
enctype="#ATTRIBUTES.pageInfo.formEncType#"> + + + +
+
+ + + + +
+ #title# +
+
+ #controls# +
+
+
+ +
+ + + + #ATTRIBUTES.pageInfo.status.errorMessage# + + + + + + +
+ + + +
+ + +
+ + + +
+ + + + + +
diff --git a/layout/render_query.cfm b/layout/render_query.cfm new file mode 100644 index 0000000..1cacb9d --- /dev/null +++ b/layout/render_query.cfm @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + +
#col#
#ATTRIBUTES.query[col]#
+
\ No newline at end of file diff --git a/layout/xls.cfm b/layout/xls.cfm new file mode 100644 index 0000000..5d8a964 --- /dev/null +++ b/layout/xls.cfm @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#title##fieldArray[i]#
#dateFormat(data,'YYYY-MM-DD')# #timeFormat(data,'HH:mm')##Replace(data, '.', ',')##data##data#
+
+
+ + + + + + \ No newline at end of file diff --git a/layout/xlshtm.cfm b/layout/xlshtm.cfm new file mode 100644 index 0000000..b74ad64 --- /dev/null +++ b/layout/xlshtm.cfm @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#structFind(ATTRIBUTES.titleMap,field).title#
+ #ATTRIBUTES.qRead[field]# +
+ + +
+
+ + + + \ No newline at end of file diff --git a/layout/xml.cfm b/layout/xml.cfm new file mode 100644 index 0000000..65e7e41 --- /dev/null +++ b/layout/xml.cfm @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + xls-generator + + + + + + + + + + + + + + + ss:ExpandedColumnCount="#ListLen(qRead.ColumnList)#" + + ss:ExpandedRowCount="#(qRead.RecordCount + 1)#" + x:FullColumns="1" + x:FullRows="1"> + + + + + + + + + + + + + + + + + + select coalesce(max(length(#field#)),0) as maxlen from qRead + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #columns[i].title# + + + + + + + ss:StyleID="DateTime">#dateFormat(qRead[field],"YYYY-MM-DD")#T#timeFormat(qRead[field],"HH:mm:ss.l")##qRead[field]#
+ +
+ +
+ +
+ + + + + + + + \ No newline at end of file diff --git a/lib/settings.cfm b/lib/settings.cfm index c7e5784..4d1505a 100644 --- a/lib/settings.cfm +++ b/lib/settings.cfm @@ -183,10 +183,7 @@ - + diff --git a/payg.cfm b/payg.cfm new file mode 100644 index 0000000..c4671ee --- /dev/null +++ b/payg.cfm @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + + + + + + select * from ( + values + ('Объектное хранилище S3 CEPH', 'Дисковое пространство: Объем хранения','paas.s3.ceph.vol-m','ГБайт',1.80,0) + ,('Объектное хранилище S3 CEPH','Исходящий трафик','paas.s3.ceph.trf-m','ГБайт',1.50,0) + ,('Объектное хранилище S3 CEPH','Запросы GET, HEAD, OPTIONS','paas.s3.ceph.get-m','10тыс.шт.',0.35,0) + ,('Объектное хранилище S3 CEPH','Запросы PUT, POST, PATCH','paas.s3.ceph.put-m','10тыс.шт.',4.50,0) + ) as + s (svc, component, code, unit, price, discount) + order by code + + + + + + + select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name, + case + when vdc.name like '%-v1cl1%' then 'iaas.ngc.i29' + when vdc.name like '%-v1cl2%' then 'iaas.ngc.i31' + when vdc.name like '%-v1cl4%' then 'iaas.ngc.a28' + when vdc.name like '%-v1cl6%' then 'iaas.ngc.i28' + else '['||vdc.name||']' end as code, + sum(cpu_used/cpu_speed)/4. as core_h, + sum(mem_used)/1024/4. as gb_h + from ngcloud_ru.capacity_resource + join ngcloud_ru.vdc on capacity_resource.vdc_id=vdc.id + join ngcloud_ru.tenant on tenant.id=vdc.tenant_id + where tenant.wzcode = + AND capacity_resource.timestamp >= + AND capacity_resource.timestamp < + group by tenant.wzcode, vdc.name + order by tenant.wzcode, vdc.name; + + + + + + + + + select max(capacity_resource.timestamp) as dt_load from ngcloud_ru.capacity_resource + + + + + + select 'WZ'||to_char(tenant.wzcode,'FM00000') as wz, vdc.name as vdc_name, + case + WHEN vdc.name LIKE '%-v1cl1%' THEN 'iaas.ngc.i29' + WHEN vdc.name LIKE '%-v1cl2%' THEN 'iaas.ngc.i31' + WHEN vdc.name LIKE '%-v1cl4%' THEN 'iaas.ngc.a28' + WHEN vdc.name LIKE '%-v1cl6%' THEN 'iaas.ngc.i28' + ELSE '['||vdc.name||']' END + || CASE + WHEN storage_profile_types.name ILIKE '%-SSD%' THEN '.ssd-m' + WHEN storage_profile_types.name ILIKE '%-SAS' THEN '.sas-m' + WHEN storage_profile_types.name ILIKE '%-SATA' THEN '.sata-m' + ELSE '.['|| storage_profile_types.name ||']' END + as code, + storage_profile_types.name, -- *** это не тип, а профайл + sum("limit")/1024./4 as gb_h_limit, -- 4 потому, что сбор раз в 15 минут + sum(used)/1024./4 as gb_h_used + from ngcloud_ru.capacity_storage + join ngcloud_ru.vdc on capacity_storage.vdc_id=vdc.id + join ngcloud_ru.tenant on tenant.id=vdc.tenant_id + join ngcloud_ru.storage_profile_types on capacity_storage.storage_profile_types_id=storage_profile_types.id + where tenant.wzcode = + AND capacity_storage.timestamp >= + AND capacity_storage.timestamp < + group by tenant.wzcode, vdc.name, storage_profile_types.name + order by tenant.wzcode, vdc.name, storage_profile_types.name; + + + select max(capacity_storage.timestamp) as dt_load from ngcloud_ru.capacity_storage + + + + + + + + + + + select /* *** ниже дублирование кода агрегации - round ceil etc, обратить внимание при правке */ + (sum(bucket_stat.usage_rgw_main_size_actual)/) as vol_B + ,ceil(sum(bucket_stat.usage_rgw_main_size_actual)//1024/1024/1024) as vol_GB + ,greatest(ceil(sum(bucket_stat.usage_rgw_main_size_actual)/ + /1024/1024/1024)- + case when bucket_stat.placement_id = 1 then 1 else 0 end, 0) as vol_GB_free_tier_subtracted /*считается не в точности так, как в функции*/ + ,case + when bucket_stat.placement_id = 1 then 'paas.s3.ceph' + when bucket_stat.placement_id = 2 then 'paas.s3.cphc' + else '['|| TO_CHAR(bucket_stat.placement_id,'FM9') ||']' end as code + --,bucket_stat.placement_id + ,'WZ'||lpad(bucket_stat.owner, 5, '0') as wz -- *** здесь не число, а строка, поэтому другая формула обратной сборки WZ + + from s3billing.bucket_stat + join s3billing.placement ON s3billing.placement.id=bucket_stat.placement_id + join s3billing.bucket_info ON bucket_info.id=bucket_stat.bucket_id + where bucket_stat.placement_id in (1,2) + AND bucket_stat.owner = + AND bucket_stat.timestamp_addition >= + AND bucket_stat.timestamp_addition < + group by bucket_stat.owner, bucket_stat.placement_id + order by bucket_stat.owner, bucket_stat.placement_id; + + + + + + + + + select max(timestamp_addition) as dt_load from s3billing.bucket_stat + + + +select + sum( + CASE WHEN + (category.name LIKE 'get%' + OR category.name LIKE 'head%' + OR category.name LIKE 'options%' + ) THEN ops ELSE 0 END + ) as get + ,ceil(sum( + CASE WHEN + (category.name LIKE 'get%' + OR category.name LIKE 'head%' + OR category.name LIKE 'options%' + ) THEN ops ELSE 0 END + )/10000) as get_10k + ,greatest(ceil(sum( + CASE WHEN + (category.name LIKE 'get%' + OR category.name LIKE 'head%' + OR category.name LIKE 'options%' + ) THEN ops ELSE 0 END + )/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 10 ELSE 0 END, 0 + ) as get_10k_free_tier_subtracted + + ,sum( + CASE WHEN + (category.name LIKE 'put%' + OR category.name LIKE 'post%' + OR category.name LIKE 'patch%' + OR category.name LIKE 'list%' + ) THEN ops ELSE 0 END + ) as put + ,ceil(sum( + CASE WHEN + (category.name LIKE 'put%' + OR category.name LIKE 'post%' + OR category.name LIKE 'patch%' + OR category.name LIKE 'list%' + ) THEN ops ELSE 0 END + )/10000) as put_10k + ,greatest(ceil(sum( + CASE WHEN + (category.name LIKE 'put%' + OR category.name LIKE 'post%' + OR category.name LIKE 'patch%' + OR category.name LIKE 'list%' + ) THEN ops ELSE 0 END + )/10000) - CASE WHEN bucket_info.placement_id = 1 THEN 1 ELSE 0 END, 0 + ) as put_10k_free_tier_subtracted + + ,(sum(bytes_sent)) as bytes_sent + ,ceil(sum(bytes_sent)/1024/1024/1024) as bytes_sent_GB + ,greatest(ceil(sum(bytes_sent)/1024/1024/1024) - CASE WHEN bucket_info.placement_id = 1 THEN 100 ELSE 0 END, 0 + ) as bytes_sent_GB_free_tier_subtracted + + ,case + when bucket_info.placement_id = 1 then 'paas.s3.ceph' + when bucket_info.placement_id = 2 then 'paas.s3.cphc' + else '['|| TO_CHAR(bucket_info.placement_id,'FM9') ||']' end as code --*** зачем делать там ключ bigint + ,bucket_info.placement_id + --category.name, bucket_info.name + ,'WZ'||lpad(user_info.name, 5, '0') as wz + from s3billing.usage_bucket_by_user + join s3billing.user_info on usage_bucket_by_user.user_id=user_info.id + join s3billing.category on usage_bucket_by_user.category_id=category.id + join s3billing.bucket_info on usage_bucket_by_user.bucketid=bucket_info.id + join s3billing.placement on bucket_info.placement_id=placement.id + where 1=1 + AND user_info.name = + AND usage_bucket_by_user.time >= + AND usage_bucket_by_user.time < + group by user_info.name, bucket_info.placement_id + order by user_info.name, bucket_info.placement_id; + + + + + + + + + select max(time) as dt_load from s3billing.usage_bucket_by_user + + + + +select wz, code || '.vcpu-m' as code, core_h as raw_metric, core_h as metric, core_h as chargeable_metric from qComputing +union all +select wz, code || '.ram-m' as code, gb_h as raw_metric, gb_h as metric, gb_h as chargeable_metric from qComputing +union all +select wz, code, gb_h_used as raw_metric, gb_h_used as metric, gb_h_used as chargeable_metric from qStorage +union all +select wz, code || '.vol-m', vol_b as raw_metric, vol_gb as metric, vol_GB_free_tier_subtracted as chargeable_metric from qS3Vol +union all +select wz, code || '.get-m', get as raw_metric, get_10k as metric, get_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf +union all +select wz, code || '.put-m', put as raw_metric, put_10k as metric, put_10k_free_tier_subtracted as chargeable_metric from qS3OpsTrf +union all +select wz, code || '.trf-m', bytes_sent as raw_metric, bytes_sent_gb as metric, bytes_sent_gb_free_tier_subtracted as chargeable_metric from qS3OpsTrf + + + + + + + +SELECT + + s.code + s.svc + s.component + m.chargeable_metric + s.unit + s.price*(100-s.discount)/100 as discounted_price + s.price*(100-s.discount)/100*m.chargeable_metric as charge + + + s.price + s.discount + m.raw_metric + m.metric + + + +FROM qSpec as s, qUnifiedMetric as m +WHERE m.wz= AND s.code=m.code +order by s.code + + + + + + + + + + + + + + + Отчет по PAYG + + + + + + + + + + +
+Период с +по + + +
+Часов в периоде: #hours# Строк в отчете: #qCharge.recordCount#
+Актуальность данных: +VCD Computing: #dateFormat(qComputingAge.dt_load,'YYYY-MM-DD')# #timeFormat(qComputingAge.dt_load,'HH:MM:SS')# +VCD Storage: #dateFormat(qStorageAge.dt_load,'YYYY-MM-DD')# #timeFormat(qStorageAge.dt_load,'HH:MM:SS')# +S3 хранение: #dateFormat(qS3VolAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3VolAge.dt_load,'HH:MM:SS')# +S3 операции и трафик: #dateFormat(qS3OpsTrfAge.dt_load,'YYYY-MM-DD')# #timeFormat(qS3OpsTrfAge.dt_load,'HH:MM:SS')# + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
АртикулКол-во (метрика)Ед.изм.Цена ₽ со скид., с НДССтоимость ₽ с НДС   УслугаКомпонентGPL с НДССкидка%Оплачиваемый объем
#svc#
#currentRow##code##chargeable_metric##ed_izm##discounted_price##charge##svc##component##price##discount##metric#
Итого#svc#:#NumFmt(acc,2)#
+ + + + + + +