cpee-model-management 1.0.18 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0f20ba70c3f8b275794d93cc37318ea2c9a2f6cac142b97955b7df37bf19c78
4
- data.tar.gz: 727d1d7684b81ce572a09fb6afa63365e74c7f9d40d231fb8495d7797f3f2057
3
+ metadata.gz: 2407951bdeabf8fad81810a6c56b3ce1f8a28d17e583d6c32207424cdc11334a
4
+ data.tar.gz: 9286ff4e9aa86127c7ce19ab0bd0da71b596b6ef035a99b48bea5bc4e85f1383
5
5
  SHA512:
6
- metadata.gz: 6d765472f0d8e08bbc6a43e2e6fb779065ee86606cd5030ff82a9e69134f29a01afcad618c81d089a66d06b893f6f64133555ef578ed2a9e9c1504faedd8f65f
7
- data.tar.gz: 522152b30e278e976ae047cd4a355f40f73e19d8abf7ddb809e1385bd39007e9f6b1904b3f98d8334dd031f1d1fb30af4952581978128219f521741c401669f4
6
+ metadata.gz: 27df5a985c2441e656cfaefcb72377bbf720d04fe21c49fb9866c2b1b42d314af515f3dba981e8afb4fb616d2a9cdc897af8fd048d7547f57cfac594cac0ab1c
7
+ data.tar.gz: 076150342b2320ac0103a245f2162e7c03450970c9d078cd1446b1f400996dea35f4350a0aacbeed696344d3d996337531e7a25daa42ab9e755b3c8687ef05cb
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "cpee-model-management"
3
- s.version = "1.0.18"
3
+ s.version = "1.1.0"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.license = "LGPL-3.0"
6
6
  s.summary = "(Lifecycle) manage your process models in a directory or git repo."
@@ -25,6 +25,7 @@ require 'fileutils'
25
25
  require 'pathname'
26
26
  require 'shellwords'
27
27
  require 'securerandom'
28
+ require 'cpee/redis'
28
29
 
29
30
  module CPEE
30
31
  module ModelManagement
@@ -507,6 +508,26 @@ module CPEE
507
508
  nil
508
509
  end
509
510
  end #}}}
511
+ class ShowUrl < Riddl::Implementation #{{{
512
+ def response
513
+ show = @a[0]
514
+ @status = 302
515
+ @headers << Riddl::Header.new('Location',show + @p.first.value)
516
+ end
517
+ end #}}}
518
+ class AbandonUrl < Riddl::Implementation #{{{
519
+ def response
520
+ aba = @p.first.value
521
+ res1 = Typhoeus.get(File.join(aba,'properties','state','/'))
522
+ if res1.success?
523
+ if res1.response_body == 'ready' || res1.response_body == 'stopped'
524
+ Typhoeus.put(File.join(aba,'properties','state','/'), headers: {'Content-Type' => 'application/x-www-form-urlencoded'}, body: "value=abandoned")
525
+ end
526
+ end
527
+ nil
528
+ end
529
+ end #}}}
530
+
510
531
  class MoveItem < Riddl::Implementation #{{{
511
532
  def response
512
533
  where = @a[0] == :main ? '' : Riddl::Protocols::Utils::unescape(@r[-2])
@@ -606,7 +627,7 @@ module CPEE
606
627
  end
607
628
  end #}}}
608
629
 
609
- class Active < Riddl::SSEImplementation #{{{
630
+ class ManagementSend < Riddl::SSEImplementation #{{{
610
631
  def onopen
611
632
  @conns = @a[0]
612
633
  @conns << self
@@ -616,31 +637,244 @@ module CPEE
616
637
  end
617
638
  end #}}}
618
639
 
640
+ class StatSend < Riddl::SSEImplementation #{{{
641
+ def onopen
642
+ @conns = @a[0]
643
+ @conns << self
644
+ end
645
+ def onclose
646
+ @conns.delete(self)
647
+ end
648
+ end #}}}
649
+
650
+ class StatReceive < Riddl::Implementation #{{{
651
+ def response
652
+ redis = @a[0]
653
+ receivers = @a[1]
654
+ topic = @p[1].value
655
+ event_name = @p[2].value
656
+ notification = JSON.parse(@p[3].value.read)
657
+
658
+ instancenr = notification['instance']
659
+ content = notification['content']
660
+ attr = content['attributes']
661
+ engine = notification['cpee']
662
+
663
+ prefix = File.join(engine,notification['instance-uuid'].to_s)
664
+
665
+ if topic == 'state' && event_name == 'change'
666
+ if %w{abandoned finished}.include?(content['state'])
667
+ parent = redis.get(File.join(prefix,'parent'))
668
+ oldstate = redis.get(File.join(prefix,'state'))
669
+ children = redis.lrange(File.join(prefix,'children'),0,-1)
670
+ redis.multi do |multi|
671
+ multi.decr(File.join(engine,oldstate)) rescue nil
672
+ multi.incr(File.join(engine,'total_' + content['state']))
673
+ multi.lrem(File.join(engine,'instances'),0,notification['instance-uuid'])
674
+ multi.del(File.join(prefix,'instance-url'))
675
+ multi.del(File.join(prefix,'author'))
676
+ multi.del(File.join(prefix,'path'))
677
+ multi.del(File.join(prefix,'name'))
678
+ multi.del(File.join(prefix,'state'))
679
+ multi.del(File.join(prefix,'cpu'))
680
+ multi.del(File.join(prefix,'mem'))
681
+ children.each do |child|
682
+ if parent
683
+ multi.set(File.join(engine,child,'parent'),parent)
684
+ else
685
+ multi.del(File.join(engine,child,'parent'))
686
+ end
687
+ end
688
+ multi.del(File.join(prefix,'children'))
689
+ multi.del(File.join(prefix,'parent'))
690
+ if parent
691
+ multi.lrem(File.join(engine,parent,'children'),0,notification['instance-uuid'].to_s)
692
+ end
693
+ end
694
+ elsif %w{ready}.include?(content['state'])
695
+ exi = true if redis.lrange(File.join(engine,'instances'),0,-1).include?(notification['instance-uuid'])
696
+ redis.multi do |multi|
697
+ unless exi
698
+ multi.incr(File.join(engine,'total_created'))
699
+ multi.incr(File.join(engine,'ready'))
700
+ multi.rpush(File.join(engine,'instances'),notification['instance-uuid'])
701
+ end
702
+ multi.set(File.join(prefix,'instance-url'),notification['instance-url'])
703
+ multi.set(File.join(prefix,'author'),attr['author'])
704
+ multi.set(File.join(prefix,'state'),content['state'])
705
+ multi.set(File.join(prefix,'path'),File.join(attr['design_dir'],attr['info']+'.xml')) unless attr['design_dir'].nil? || attr['info'].nil?
706
+ multi.set(File.join(prefix,'name'),attr['info'])
707
+ multi.set(File.join(prefix,'cpu'),0)
708
+ multi.set(File.join(prefix,'mem'),0)
709
+ end
710
+ elsif %w{stopping}.include?(content['state'])
711
+ redis.set(File.join(prefix,'state'),content['state'])
712
+ elsif %w{stopped}.include?(content['state'])
713
+ redis.multi do |multi|
714
+ multi.decr(File.join(engine,'running'))
715
+ multi.incr(File.join(engine,'stopped'))
716
+ multi.set(File.join(prefix,'state'),content['state'])
717
+ multi.set(File.join(prefix,'cpu'),0)
718
+ multi.set(File.join(prefix,'mem'),0)
719
+ end
720
+ elsif %w{running}.include?(content['state'])
721
+ oldstate = redis.get(File.join(prefix,'state'))
722
+ redis.multi do |multi|
723
+ multi.decr(File.join(engine,oldstate)) rescue nil
724
+ multi.incr(File.join(engine,'running'))
725
+ multi.set(File.join(prefix,'state'),content['state'])
726
+ end
727
+ end
728
+
729
+ url, author, path, name, state, parent = redis.mget(
730
+ File.join(prefix,'instance-url'),
731
+ File.join(prefix,'author'),
732
+ File.join(prefix,'path'),
733
+ File.join(prefix,'name'),
734
+ File.join(prefix,'state'),
735
+ File.join(prefix,'parent')
736
+ )
737
+ receivers.each do |conn|
738
+ conn.send JSON::generate(:topic => topic, :event => event_name, :engine => engine, :uuid => notification['instance-uuid'], :url => url, :author => author, :path => path.to_s, :name => name, :state => content['state'], :parent => parent.to_s)
739
+ end
740
+ elsif topic == 'task' && event_name == 'instantiation'
741
+ redis.multi do |multi|
742
+ multi.rpush(File.join(engine,notification['instance-uuid'],'children'),content['received']['CPEE-INSTANCE-UUID'])
743
+ multi.set(File.join(engine,content['received']['CPEE-INSTANCE-UUID'],'parent'),notification['instance-uuid'])
744
+ end
745
+ prefix = File.join(engine,content['received']['CPEE-INSTANCE-UUID'].to_s)
746
+ url, author, path, name, state, parent = redis.mget(
747
+ File.join(prefix,'instance-url'),
748
+ File.join(prefix,'author'),
749
+ File.join(prefix,'path'),
750
+ File.join(prefix,'name'),
751
+ File.join(prefix,'state'),
752
+ File.join(prefix,'parent')
753
+ )
754
+ receivers.each do |conn|
755
+ conn.send JSON::generate(:topic => 'state', :event => 'change', :engine => engine, :uuid => content['received']['CPEE-INSTANCE-UUID'], :url => url, :author => author, :path => path.to_s, :name => name, :state => state, :parent => parent.to_s)
756
+ end
757
+ elsif topic == 'status' && event_name == 'resource_utilization'
758
+ redis.multi do |multi|
759
+ multi.set(File.join(prefix,'cpu'),content['utime'] + content['stime'])
760
+ multi.set(File.join(prefix,'mem'),content['mib'])
761
+ end
762
+ receivers.each do |conn|
763
+ conn.send JSON::generate(:topic => topic, :event => event_name, :engine => engine, :uuid => notification['instance-uuid'], :cpu => content['utime'] + content['stime'], :mem => content['mib'])
764
+ end
765
+ elsif topic == 'node' && event_name == 'resource_utilization'
766
+ redis.multi do |multi|
767
+ multi.set(File.join(engine,'cpu_usage'),content['cpu_usage'])
768
+ multi.set(File.join(engine,'mem_free'),content['mem_free'])
769
+ multi.set(File.join(engine,'mem_total'),content['mem_total'])
770
+ multi.set(File.join(engine,'mem_available'),content['mem_available'])
771
+ end
772
+ receivers.each do |conn|
773
+ conn.send JSON::generate(:topic => topic, :event => event_name, :engine => engine, :cpu_usage => content['cpu_usage'], :mem_free => content['mem_free'], :mem_total => content['mem_total'], :mem_available => content['mem_available'])
774
+ end
775
+ end
776
+ end
777
+ end #}}}
778
+
779
+ class StatGet < Riddl::Implementation #{{{
780
+ def response
781
+ redis = @a[0]
782
+ engine = @p[0].value
783
+ res = redis.mapped_mget(
784
+ File.join(engine,'total_created'),
785
+ File.join(engine,'total_finished'),
786
+ File.join(engine,'total_abandoned'),
787
+ File.join(engine,'ready'),
788
+ File.join(engine,'stopped'),
789
+ File.join(engine,'running')
790
+ ).transform_keys{ |k| File.basename(k) }.transform_values(&:to_i)
791
+ Riddl::Parameter::Complex.new('stats','application/json',JSON::pretty_generate(res || []))
792
+ end
793
+ end #}}}
794
+ class InstancesGet < Riddl::Implementation #{{{
795
+ def response
796
+ redis = @a[0]
797
+ engine = @p[0].value
798
+ doc = XML::Smart.string('<instances/>')
799
+ redis.lrange(File.join(engine,'instances'),0,-1).each do |i|
800
+ prefix = File.join(engine,i.to_s)
801
+ url, author, path, name, state, cpu, mem, parent = redis.mget(
802
+ File.join(prefix,'instance-url'),
803
+ File.join(prefix,'author'),
804
+ File.join(prefix,'path'),
805
+ File.join(prefix,'name'),
806
+ File.join(prefix,'state'),
807
+ File.join(prefix,'cpu'),
808
+ File.join(prefix,'mem'),
809
+ File.join(prefix,'parent')
810
+ )
811
+ doc.root.add('instance', :uuid => i, :url => url, :author => author, :path => path, :name => name, :state => state, :cpu => cpu, :mem => mem, :parent => parent)
812
+ end
813
+ Riddl::Parameter::Complex.new('tree','text/xml',doc.to_s)
814
+ end
815
+ end #}}}
816
+ class InstanceGet < Riddl::Implementation #{{{
817
+ def response
818
+ redis = @a[0]
819
+ engine = @p[0].value
820
+ uuid = @r[-1]
821
+ prefix = File.join(engine,uuid.to_s)
822
+ url, author, path, name, state, cpu, mem, parent = redis.mget(
823
+ File.join(prefix,'instance-url'),
824
+ File.join(prefix,'author'),
825
+ File.join(prefix,'path'),
826
+ File.join(prefix,'name'),
827
+ File.join(prefix,'state'),
828
+ File.join(prefix,'cpu'),
829
+ File.join(prefix,'mem'),
830
+ File.join(prefix,'parent')
831
+ )
832
+ Riddl::Parameter::Complex.new('instance','application/json',JSON.generate(:uuid => uuid, :url => url, :author => author, :path => path, :name => name, :state => state, :cpu => cpu, :mem => mem, :parent => parent))
833
+ end
834
+ end #}}}
835
+
836
+
619
837
  def self::implementation(opts)
620
- opts[:connections] = []
838
+ opts[:management_receivers] = []
839
+ opts[:stat_receivers] = []
840
+
841
+ ### set redis_cmd to nil if you want to do global
842
+ ### at least redis_path or redis_url and redis_db have to be set if you do global
843
+ opts[:redis_path] ||= 'redis.sock' # use e.g. /tmp/redis.sock for global stuff. Look it up in your redis config
844
+ opts[:redis_db] ||= 0
845
+ ### optional redis stuff
846
+ opts[:redis_url] ||= nil
847
+ opts[:redis_cmd] ||= 'redis-server --port 0 --unixsocket #redis_path# --unixsocketperm 600 --pidfile #redis_pid# --dir #redis_db_dir# --dbfilename #redis_db_name# --databases 1 --save 900 1 --save 300 10 --save 60 10000 --rdbcompression yes --daemonize yes'
848
+ opts[:redis_pid] ||= 'redis.pid' # use e.g. /var/run/redis.pid if you do global. Look it up in your redis config
849
+ opts[:redis_db_name] ||= 'redis.rdb' # use e.g. /var/lib/redis.rdb for global stuff. Look it up in your redis config
850
+
851
+ CPEE::redis_connect opts, 'Server Main'
621
852
 
622
853
  Proc.new do
623
- on resource do
854
+ interface 'events' do
855
+ run StatReceive, opts[:redis], opts[:stat_receivers] if post 'event'
856
+ end
857
+ interface 'implementation' do
624
858
  run GetList, :main, opts[:views], opts[:models] if get 'stage'
625
859
  run GetListFull, opts[:views], opts[:models] if get 'full'
626
860
  run GetStages, opts[:themes] if get 'stages'
627
- run Create, :main, :cre, opts[:views], opts[:connections], opts[:templates], opts[:models] if post 'item'
628
- run Create, :main, :dup, opts[:views], opts[:connections], opts[:templates], opts[:models] if post 'duplicate'
629
- run CreateDir, opts[:connections], opts[:models] if post 'dir'
630
- run Active, opts[:connections] if sse
861
+ run Create, :main, :cre, opts[:views], opts[:management_receivers], opts[:templates], opts[:models] if post 'item'
862
+ run Create, :main, :dup, opts[:views], opts[:management_receivers], opts[:templates], opts[:models] if post 'duplicate'
863
+ run CreateDir, opts[:management_receivers], opts[:models] if post 'dir'
864
+ run ManagementSend, opts[:management_receivers] if sse
631
865
  on resource '[a-zA-Z0-9öäüÖÄÜ _-]+\.dir' do
632
866
  run GetList, :sub, opts[:views], opts[:models] if get 'stage'
633
- run Create, :sub, :cre, opts[:views], opts[:connections], opts[:templates], opts[:models] if post 'item'
634
- run Create, :sub, :dup, opts[:views], opts[:connections], opts[:templates], opts[:models] if post 'duplicate'
635
- run DeleteDir, opts[:connections], opts[:models] if delete
636
- run RenameDir, opts[:connections], opts[:models] if put 'name'
867
+ run Create, :sub, :cre, opts[:views], opts[:management_receivers], opts[:templates], opts[:models] if post 'item'
868
+ run Create, :sub, :dup, opts[:views], opts[:management_receivers], opts[:templates], opts[:models] if post 'duplicate'
869
+ run DeleteDir, opts[:management_receivers], opts[:models] if delete
870
+ run RenameDir, opts[:management_receivers], opts[:models] if put 'name'
637
871
  on resource '[a-zA-Z0-9öäüÖÄÜ _-]+\.xml' do
638
- run DeleteItem, :sub, opts[:connections], opts[:models] if delete
872
+ run DeleteItem, :sub, opts[:management_receivers], opts[:models] if delete
639
873
  run GetItem, :sub, opts[:models] if get
640
- run PutItem, :sub, opts[:connections], opts[:models] if put 'content'
641
- run RenameItem, :sub, opts[:connections], opts[:models] if put 'name'
642
- run MoveItem, :sub, opts[:connections], opts[:models] if put 'dirname'
643
- run ShiftItem, :sub, opts[:connections], opts[:themes], opts[:models] if put 'newstage'
874
+ run PutItem, :sub, opts[:management_receivers], opts[:models] if put 'content'
875
+ run RenameItem, :sub, opts[:management_receivers], opts[:models] if put 'name'
876
+ run MoveItem, :sub, opts[:management_receivers], opts[:models] if put 'dirname'
877
+ run ShiftItem, :sub, opts[:management_receivers], opts[:themes], opts[:models] if put 'newstage'
644
878
  on resource 'open' do
645
879
  run OpenItem, :sub, opts[:instantiate], opts[:cockpit], opts[:views], false, opts[:models] if get 'stage'
646
880
  end
@@ -650,12 +884,12 @@ module CPEE
650
884
  end
651
885
  end
652
886
  on resource '[a-zA-Z0-9öäüÖÄÜ _-]+\.xml' do
653
- run DeleteItem, :main, opts[:connections], opts[:models] if delete
887
+ run DeleteItem, :main, opts[:management_receivers], opts[:models] if delete
654
888
  run GetItem, :main, opts[:models] if get
655
- run PutItem, :main, opts[:connections], opts[:models] if put 'content'
656
- run RenameItem, :main, opts[:connections], opts[:models] if put 'name'
657
- run MoveItem, :main, opts[:connections], opts[:models] if put 'dirname'
658
- run ShiftItem, :main, opts[:connections], opts[:themes], opts[:models] if put 'newstage'
889
+ run PutItem, :main, opts[:management_receivers], opts[:models] if put 'content'
890
+ run RenameItem, :main, opts[:management_receivers], opts[:models] if put 'name'
891
+ run MoveItem, :main, opts[:management_receivers], opts[:models] if put 'dirname'
892
+ run ShiftItem, :main, opts[:management_receivers], opts[:themes], opts[:models] if put 'newstage'
659
893
  on resource 'open' do
660
894
  run OpenItem, :main, opts[:instantiate], opts[:cockpit], opts[:views], false, opts[:models] if get 'stage'
661
895
  end
@@ -663,6 +897,26 @@ module CPEE
663
897
  run OpenItem, :main, opts[:instantiate], opts[:cockpit], opts[:views], true, opts[:models] if get 'stage'
664
898
  end
665
899
  end
900
+ on resource 'dash' do
901
+ on resource 'show' do
902
+ run ShowUrl, opts[:show] if get 'url'
903
+ end
904
+ on resource 'abandon' do
905
+ run AbandonUrl if put 'url'
906
+ end
907
+ on resource 'events' do
908
+ run StatSend, opts[:stat_receivers] if sse
909
+ end
910
+ on resource 'instances' do
911
+ run InstancesGet, opts[:redis] if get 'engine'
912
+ on resource do
913
+ run InstanceGet, opts[:redis] if get 'engine'
914
+ end
915
+ end
916
+ on resource 'stats' do
917
+ run StatGet, opts[:redis] if get 'engine'
918
+ end
919
+ end
666
920
  end
667
921
  end
668
922
  end
@@ -0,0 +1,133 @@
1
+ <description xmlns="http://riddl.org/ns/description/1.0" xmlns:ann="http://riddl.org/ns/annotation/1.0" xmlns:xi="http://www.w3.org/2001/XInclude" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
2
+ <message name="url">
3
+ <parameter name="url" type="string"/>
4
+ </message>
5
+ <message name="engine">
6
+ <parameter name="engine" type="string"/>
7
+ </message>
8
+ <message name="stats">
9
+ <parameter name="stats" mimetype="application/json"/>
10
+ </message>
11
+ <message name="tree">
12
+ <parameter name="tree" mimetype="text/xml"/>
13
+ </message>
14
+ <message name="instance">
15
+ <parameter name="instance" mimetype="application/json"/>
16
+ </message>
17
+ <message name="item">
18
+ <parameter name="stage" type="string">
19
+ <xi:include href="stages"/>
20
+ </parameter>
21
+ <parameter name="new" type="string">
22
+ <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+</param>
23
+ </parameter>
24
+ </message>
25
+ <message name="name">
26
+ <parameter name="new" type="string">
27
+ <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+</param>
28
+ </parameter>
29
+ </message>
30
+ <message name="dir">
31
+ <parameter name="dir" type="string">
32
+ <param name="pattern">([a-zA-Z0-9öäüÖÄÜ _-]+)|</param>
33
+ </parameter>
34
+ </message>
35
+ <message name="dirname">
36
+ <parameter name="dir" type="string">
37
+ <param name="pattern">([a-zA-Z0-9öäüÖÄÜ _-]+)\.dir|</param>
38
+ </parameter>
39
+ </message>
40
+ <message name="duplicate">
41
+ <parameter name="new" type="string">
42
+ <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+</param>
43
+ </parameter>
44
+ <parameter name="old" type="string">
45
+ <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+\.xml</param>
46
+ </parameter>
47
+ </message>
48
+ <message name="stages">
49
+ <parameter name="stages" type="string"/>
50
+ </message>
51
+ <message name="newstage">
52
+ <parameter name="stage" type="string">
53
+ <xi:include href="stages"/>
54
+ </parameter>
55
+ </message>
56
+ <message name="stage">
57
+ <optional>
58
+ <parameter name="stage" type="string">
59
+ <xi:include href="stages"/>
60
+ </parameter>
61
+ </optional>
62
+ </message>
63
+ <message name="full">
64
+ <parameter name="full" type="string"/>
65
+ <optional>
66
+ <parameter name="stage" type="string">
67
+ <xi:include href="stages"/>
68
+ </parameter>
69
+ </optional>
70
+ </message>
71
+ <message name="list">
72
+ <parameter name="list" mimetype="application/json"/>
73
+ </message>
74
+ <message name="content">
75
+ <parameter name="content" mimetype="application/xml"/>
76
+ </message>
77
+ <resource>
78
+ <post in="item"/>
79
+ <post in="dir"/>
80
+ <post in="duplicate"/>
81
+ <get in="stage" out="list"/>
82
+ <get in="full" out="list"/>
83
+ <get in="stages" out="list"/>
84
+ <sse/>
85
+ <resource relative="[a-zA-Z0-9&#xF6;&#xE4;&#xFC;&#xD6;&#xC4;&#xDC; _-]+\.dir">
86
+ <post in="item"/>
87
+ <post in="duplicate"/>
88
+ <get in="stage" out="list"/>
89
+ <delete/>
90
+ <put in="name"/> <!-- rename -->
91
+ <resource relative="[a-zA-Z0-9&#xF6;&#xE4;&#xFC;&#xD6;&#xC4;&#xDC; _-]+\.xml">
92
+ <get out='content'/>
93
+ <delete/>
94
+ <put in="content"/>
95
+ <put in="name"/> <!-- rename -->
96
+ <put in="dirname"/> <!-- move -->
97
+ <put in="newstage"/> <!-- shift -->
98
+ <resource relative="open"><get in="stage"/></resource>
99
+ <resource relative="open-new"><get in="stage"/></resource>
100
+ </resource>
101
+ </resource>
102
+ <resource relative="[a-zA-Z0-9&#xF6;&#xE4;&#xFC;&#xD6;&#xC4;&#xDC; _-]+\.xml">
103
+ <get out='content'/>
104
+ <delete/>
105
+ <put in="content"/>
106
+ <put in="name"/> <!-- rename -->
107
+ <put in="dirname"/> <!-- move -->
108
+ <put in="newstage"/> <!-- shift -->
109
+ <resource relative="open"><get in="stage"/></resource>
110
+ <resource relative="open-new"><get in="stage"/></resource>
111
+ </resource>
112
+ <resource relative="dash">
113
+ <resource relative="show">
114
+ <get in="url"/>
115
+ </resource>
116
+ <resource relative="abandon">
117
+ <put in="url"/>
118
+ </resource>
119
+ <resource relative="events">
120
+ <sse/>
121
+ </resource>
122
+ <resource relative="instances">
123
+ <get in="engine" out="tree"/>
124
+ <resource>
125
+ <get in="engine" out="instance"/>
126
+ </resource>
127
+ </resource>
128
+ <resource relative="stats">
129
+ <get in="engine" out="stats"/>
130
+ </resource>
131
+ </resource>
132
+ </resource>
133
+ </description>
@@ -1,98 +1,19 @@
1
- <description xmlns="http://riddl.org/ns/description/1.0" xmlns:ann="http://riddl.org/ns/annotation/1.0" xmlns:xi="http://www.w3.org/2001/XInclude" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
2
- <message name="item">
3
- <parameter name="stage" type="string">
4
- <xi:include href="stages"/>
5
- </parameter>
6
- <parameter name="new" type="string">
7
- <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+</param>
8
- </parameter>
9
- </message>
10
- <message name="name">
11
- <parameter name="new" type="string">
12
- <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+</param>
13
- </parameter>
14
- </message>
15
- <message name="dir">
16
- <parameter name="dir" type="string">
17
- <param name="pattern">([a-zA-Z0-9öäüÖÄÜ _-]+)|</param>
18
- </parameter>
19
- </message>
20
- <message name="dirname">
21
- <parameter name="dir" type="string">
22
- <param name="pattern">([a-zA-Z0-9öäüÖÄÜ _-]+)\.dir|</param>
23
- </parameter>
24
- </message>
25
- <message name="duplicate">
26
- <parameter name="new" type="string">
27
- <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+</param>
28
- </parameter>
29
- <parameter name="old" type="string">
30
- <param name="pattern">[a-zA-Z0-9öäüÖÄÜ _-]+\.xml</param>
31
- </parameter>
32
- </message>
33
- <message name="stages">
34
- <parameter name="stages" type="string"/>
35
- </message>
36
- <message name="newstage">
37
- <parameter name="stage" type="string">
38
- <xi:include href="stages"/>
39
- </parameter>
40
- </message>
41
- <message name="stage">
42
- <optional>
43
- <parameter name="stage" type="string">
44
- <xi:include href="stages"/>
45
- </parameter>
46
- </optional>
47
- </message>
48
- <message name="full">
49
- <parameter name="full" type="string"/>
50
- <optional>
51
- <parameter name="stage" type="string">
52
- <xi:include href="stages"/>
53
- </parameter>
54
- </optional>
55
- </message>
56
- <message name="list">
57
- <parameter name="list" mimetype="application/json"/>
58
- </message>
59
- <message name="content">
60
- <parameter name="content" mimetype="application/xml"/>
61
- </message>
62
- <resource>
63
- <post in="item"/>
64
- <post in="dir"/>
65
- <post in="duplicate"/>
66
- <get in="stage" out="list"/>
67
- <get in="full" out="list"/>
68
- <get in="stages" out="list"/>
69
- <sse/>
70
- <resource relative="[a-zA-Z0-9&#xF6;&#xE4;&#xFC;&#xD6;&#xC4;&#xDC; _-]+\.dir">
71
- <post in="item"/>
72
- <post in="duplicate"/>
73
- <get in="stage" out="list"/>
74
- <delete/>
75
- <put in="name"/> <!-- rename -->
76
- <resource relative="[a-zA-Z0-9&#xF6;&#xE4;&#xFC;&#xD6;&#xC4;&#xDC; _-]+\.xml">
77
- <get out='content'/>
78
- <delete/>
79
- <put in="content"/>
80
- <put in="name"/> <!-- rename -->
81
- <put in="dirname"/> <!-- move -->
82
- <put in="newstage"/> <!-- shift -->
83
- <resource relative="open"><get in="stage"/></resource>
84
- <resource relative="open-new"><get in="stage"/></resource>
85
- </resource>
86
- </resource>
87
- <resource relative="[a-zA-Z0-9&#xF6;&#xE4;&#xFC;&#xD6;&#xC4;&#xDC; _-]+\.xml">
88
- <get out='content'/>
89
- <delete/>
90
- <put in="content"/>
91
- <put in="name"/> <!-- rename -->
92
- <put in="dirname"/> <!-- move -->
93
- <put in="newstage"/> <!-- shift -->
94
- <resource relative="open"><get in="stage"/></resource>
95
- <resource relative="open-new"><get in="stage"/></resource>
96
- </resource>
97
- </resource>
98
- </description>
1
+ <declaration xmlns="http://riddl.org/ns/declaration/1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
2
+ <interface name="implementation">
3
+ <xi:include href="implementation.xml"/>
4
+ </interface>
5
+ <interface name="events">
6
+ <xi:include href="http://www.riddl.org/ns/common-patterns/notifications-consumer/2.0/consumer.xml"/>
7
+ </interface>
8
+
9
+ <facade>
10
+ <tile>
11
+ <layer name="implementation">
12
+ <apply-to>/</apply-to>
13
+ </layer>
14
+ <layer name="events">
15
+ <apply-to>/dash/events</apply-to>
16
+ </layer>
17
+ </tile>
18
+ </facade>
19
+ </declaration>
data/server/moma.conf CHANGED
@@ -2,6 +2,7 @@
2
2
  :models: models
3
3
  :location: https://cpee.org/design/server/
4
4
  :instantiate: https://cpee.org/flow/start/
5
+ :show: https://cpee.org/flow/index.html?monitor=
5
6
  :cockpit:
6
7
  draft: https://cpee.org/flow/model.html?monitor=
7
8
  development: https://cpee.org/flow/edit.html?monitor=
data/ui/css/design.css CHANGED
@@ -26,6 +26,11 @@ ui-behind {
26
26
  color: #d0d0d0;
27
27
  }
28
28
 
29
+ ui-area > *:first-child {
30
+ padding-top: 0;
31
+ margin-top: 0;
32
+ }
33
+
29
34
  ui-behind span {
30
35
  cursor: pointer;
31
36
  }
data/ui/css/stats.css ADDED
@@ -0,0 +1,55 @@
1
+ #resources h1 {
2
+ font-size: 1.2em;
3
+ border-bottom: 0.1em solid var(--x-ui-border-color);
4
+ }
5
+
6
+ #resources table {
7
+ margin-left: 1.3em;
8
+ }
9
+
10
+ #instances h1 {
11
+ font-size: 1.2em;
12
+ border-bottom: 0.1em solid var(--x-ui-border-color);
13
+ }
14
+
15
+ .instances .text {
16
+ white-space: nowrap;
17
+ }
18
+ .instances .text > td {
19
+ display: inline-block;
20
+ white-space: nowrap;
21
+ overflow: hidden;
22
+ text-overflow: ellipsis;
23
+ padding-right: 0.5em;
24
+ padding-left: 0.5em;
25
+ }
26
+
27
+ .instances .name {
28
+ width: 12em;
29
+ }
30
+ .instances .state {
31
+ width: 7em
32
+ }
33
+ .instances .state:not([data-state=ready]):not([data-state=stopped]) > span.abandon {
34
+ display: none;
35
+ }
36
+ .instances .author {
37
+ width: 12em
38
+ }
39
+
40
+ .instances tr.sub, .instances tr.sub > td {
41
+ margin:0;
42
+ padding:0;
43
+ }
44
+
45
+ .instances .sub table {
46
+ margin-left: 0.8em;
47
+ }
48
+ .instances .sub table > tr.text > td:first-child::before {
49
+ content: '⤷';
50
+ margin-right: 0.5em;
51
+ }
52
+
53
+ .instances tr.text.even td {
54
+ background-color: var(--x-ui-content-light-background);
55
+ }
@@ -0,0 +1,7 @@
1
+ [is="x-ui-"] {
2
+ padding: 1em;
3
+ }
4
+ [is="x-ui-"] *:first-child {
5
+ padding-top: 0;
6
+ margin-top: 0;
7
+ }
data/ui/index.html CHANGED
@@ -35,6 +35,7 @@
35
35
  <script type="text/javascript" src="/js_libs/underscore.min.js"></script>
36
36
  <script type="text/javascript" src="/js_libs/jquery.caret.min.js"></script>
37
37
  <script type="text/javascript" src="/js_libs/jquery.cookie.js"></script>
38
+ <script type="text/javascript" src="/js_libs/plotly.min.js"></script>
38
39
 
39
40
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
40
41
 
@@ -52,20 +53,22 @@
52
53
 
53
54
  <!-- custom stuff, play arround -->
54
55
  <link rel="stylesheet" href="css/design.css" type="text/css"/>
56
+ <link rel="stylesheet" href="css/stats.css" type="text/css"/>
55
57
  <script type="text/javascript" src="js/design.js"></script>
58
+ <script type="text/javascript" src="js/stats.js"></script>
56
59
  </head>
57
60
  <body is="x-ui-">
58
61
  <ui-rest id="main">
59
62
  <ui-tabbar>
60
- <ui-before ></ui-before>
61
- <ui-tab class="" data-tab="models" >Models</ui-tab>
62
- <ui-tab class="inactive" data-tab="newmodel">New Model</ui-tab>
63
- <ui-tab class="inactive" data-tab="newdir" >New Dir</ui-tab>
64
- <ui-space ></ui-space>
65
- <ui-tab class="inactive" data-tab="running" >Running</ui-tab>
66
- <ui-tab class="inactive" data-tab="stopped" >Stopped</ui-tab>
67
- <ui-behind ><span></span></ui-behind>
68
- <ui-last ><a class="logo" href=".."></a></ui-last>
63
+ <ui-before ></ui-before>
64
+ <ui-tab class="" data-tab="models" >Models</ui-tab>
65
+ <ui-tab class="inactive" data-tab="newmodel" >New Model</ui-tab>
66
+ <ui-tab class="inactive" data-tab="newdir" >New Dir</ui-tab>
67
+ <ui-space ></ui-space>
68
+ <ui-tab class="inactive" data-tab="instances">Instances</ui-tab>
69
+ <ui-tab class="inactive" data-tab="resources">Resources</ui-tab>
70
+ <ui-behind ><span></span></ui-behind>
71
+ <ui-last ><a class="logo" href=".."></a></ui-last>
69
72
  </ui-tabbar>
70
73
  <ui-content class="noselect">
71
74
  <ui-area data-belongs-to-tab="models">
@@ -160,7 +163,63 @@
160
163
  <p>
161
164
  <button>New Directory</button>
162
165
  </p>
163
- </id>
166
+ </form>
167
+ </ui-area>
168
+ <ui-area data-belongs-to-tab="instances" class="inactive">
169
+ <p>
170
+ Show ready, running and stopped instances.
171
+ </p>
172
+ <template id="stats_instances">
173
+ <h1 class="stats_title">Engine: </h1>
174
+ <table class='instances'></table>
175
+ </template>
176
+ <template id="stats_instance">
177
+ <tr class="text">
178
+ <td class="name"><a href='' target='_blank'><em>no name</em></a></td>
179
+ <td class="num">(<span></span>)</td>
180
+ <td class="state"><span class='value'></span> <span class='abandon'>[<a href='#' title='abandon'>a</a>]</span></td>
181
+ <td class="author"><em>unknown</em></td>
182
+ <td class="cpu"></td>
183
+ <td>/</td>
184
+ <td class="mem"></em></td>
185
+ </tr>
186
+ <tr class="sub">
187
+ <td colspan="6"><table></table></td>
188
+ </tr>
189
+ </template>
190
+ <div id='instances'></div>
191
+ </ui-area>
192
+ <ui-area data-belongs-to-tab="resources" class="inactive">
193
+ <p>
194
+ Show statistics about instances per server, and metrics about the health of the environment.
195
+ </p>
196
+ <template id="stats_engine">
197
+ <h1 class="stats_title">Engine: </h1>
198
+ <div class="stats_plot"></div>
199
+ <div class="stats_text">
200
+ <table>
201
+ <tbody>
202
+ <tr>
203
+ <td>Total Instances <strong>Created</strong> / <strong>Finished</strong> / <strong>Abandoned</strong>:</td>
204
+ <td class='total_created'></td>
205
+ <td>/</td>
206
+ <td class='total_finished'></td>
207
+ <td>/</td>
208
+ <td class='total_abandoned'></td>
209
+ </tr>
210
+ <tr>
211
+ <td>Instances Currently <strong>Ready</strong> / <strong>Running</strong> / <strong>Stopped</strong>:</td>
212
+ <td class='current_ready'></td>
213
+ <td>/</td>
214
+ <td class='current_running'></td>
215
+ <td>/</td>
216
+ <td class='current_stopped'></td>
217
+ </tr>
218
+ </tbody>
219
+ </table>
220
+ </div>
221
+ </template>
222
+ <div id='resources'></div>
164
223
  </ui-area>
165
224
  </ui-content>
166
225
  </ui-rest>
data/ui/instances.html ADDED
@@ -0,0 +1,84 @@
1
+ <!--
2
+ This file is part of CPEE-MODEL-MANAGEMENT.
3
+
4
+ CPEE-MODEL-MANAGEMENT is free software: you can redistribute it and/or
5
+ modify it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or (at your
7
+ option) any later version.
8
+
9
+ CPEE-MODEL-MANAGEMENT is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
+ more details.
13
+
14
+ You should have received a copy of the GNU General Public License along with
15
+ CPEE-MODEL-MANAGEMENT (file LICENSE in the main directory). If not, see
16
+ <http://www.gnu.org/licenses/>.
17
+ -->
18
+
19
+ <!DOCTYPE html>
20
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
21
+ <head>
22
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
23
+ <title>Instances</title>
24
+
25
+ <!-- libs, do not modify. When local than load local libs. -->
26
+ <script type="text/javascript" src="/js_libs/jquery.min.js"></script>
27
+ <script type="text/javascript" src="/js_libs/jquery.browser.js"></script>
28
+ <script type="text/javascript" src="/js_libs/jquery.svg.min.js"></script>
29
+ <script type="text/javascript" src="/js_libs/jquery.svgdom.min.js"></script>
30
+ <script type="text/javascript" src="/js_libs/vkbeautify.js"></script>
31
+ <script type="text/javascript" src="/js_libs/util.js"></script>
32
+ <script type="text/javascript" src="/js_libs/printf.js"></script>
33
+ <script type="text/javascript" src="/js_libs/strftime.min.js"></script>
34
+ <script type="text/javascript" src="/js_libs/parsequery.js"></script>
35
+ <script type="text/javascript" src="/js_libs/underscore.min.js"></script>
36
+ <script type="text/javascript" src="/js_libs/jquery.caret.min.js"></script>
37
+ <script type="text/javascript" src="/js_libs/jquery.cookie.js"></script>
38
+ <script type="text/javascript" src="/js_libs/plotly.min.js"></script>
39
+
40
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
41
+
42
+ <script type="text/javascript" src="/js_libs/relaxngui.js"></script>
43
+
44
+ <script type="text/javascript" src="/js_libs/uidash.js"></script>
45
+ <script type="text/javascript" src="/js_libs/custommenu.js"></script>
46
+
47
+ <link rel="stylesheet" href="/js_libs/custommenu.css" type="text/css"/>
48
+ <link rel="stylesheet" href="/js_libs/uidash.css" type="text/css"/>
49
+
50
+ <link rel="stylesheet" href="/global_ui/ui.css" type="text/css"/>
51
+
52
+ <link rel="stylesheet" href="/js_libs/relaxngui.css" type="text/css"/>
53
+
54
+ <!-- custom stuff, play arround -->
55
+ <link rel="stylesheet" href="css/design.css" type="text/css"/>
56
+ <link rel="stylesheet" href="css/stats.css" type="text/css"/>
57
+ <link rel="stylesheet" href="css/stats_standalone.css" type="text/css"/>
58
+ <script type="text/javascript" src="js/stats.js"></script>
59
+ </head>
60
+ <body is="x-ui-">
61
+ <p>
62
+ Show ready, running and stopped instances.
63
+ </p>
64
+ <template id="stats_instances">
65
+ <h1 class="stats_title">Engine: </h1>
66
+ <table class='instances'></table>
67
+ </template>
68
+ <template id="stats_instance">
69
+ <tr class="text">
70
+ <td class="name"><a href='' target='_blank'><em>no name</em></a></td>
71
+ <td class="num">(<span></span>)</td>
72
+ <td class="state"><span class='value'></span> <span class='abandon'>[<a href='#' title='abandon'>a</a>]</span></td>
73
+ <td class="author"><em>unknown</em></td>
74
+ <td class="cpu"></td>
75
+ <td>/</td>
76
+ <td class="mem"></em></td>
77
+ </tr>
78
+ <tr class="sub">
79
+ <td colspan="6"><table></table></td>
80
+ </tr>
81
+ </template>
82
+ <div id='instances'></div>
83
+ </body>
84
+ </html>
data/ui/js/design.js CHANGED
@@ -44,17 +44,17 @@ function delete_it(name) {
44
44
  }
45
45
  }
46
46
 
47
- function es_init(gdir,gstage) {
47
+ function design_init(gdir,gstage) {
48
48
  var es = new EventSource('server/');
49
49
  es.onopen = function() {
50
- console.log('es open');
50
+ console.log('design open');
51
51
  };
52
52
  es.onmessage = function(e) {
53
53
  paint(gdir,gstage);
54
54
  };
55
55
  es.onerror = function() {
56
- console.log('es error');
57
- // es_init();
56
+ console.log('design error');
57
+ // design_init();
58
58
  };
59
59
  }
60
60
 
@@ -114,7 +114,7 @@ $(document).ready(function() {
114
114
  gstage = urlParams.get('stage') || 'draft';
115
115
  gdir = urlParams.get('dir') ? (urlParams.get('dir') + '/').replace(/\/+/,'/') : '';
116
116
 
117
- es_init(gdir,gstage);
117
+ design_init(gdir,gstage);
118
118
 
119
119
  var shifts = []
120
120
  $.ajax({
data/ui/js/stats.js ADDED
@@ -0,0 +1,223 @@
1
+ var value_count = 100
2
+
3
+ function resource_update(ename) {
4
+ var iname = ename.replace(/[^a-z0-9A-Z]/g,'-').replace(/-$/,'')
5
+ $.get('server/dash/stats/',{ engine: ename },function(data){
6
+ $('#resource_utilization_text_' + iname + ' .total_created').text(data.total_created)
7
+ $('#resource_utilization_text_' + iname + ' .total_finished').text(data.total_finished)
8
+ $('#resource_utilization_text_' + iname + ' .total_abandoned').text(data.total_abandoned)
9
+ $('#resource_utilization_text_' + iname + ' .current_ready').text(data.ready)
10
+ $('#resource_utilization_text_' + iname + ' .current_running').text(data.running)
11
+ $('#resource_utilization_text_' + iname + ' .current_stopped').text(data.stopped)
12
+ });
13
+ }
14
+
15
+ function resource_add(ename) {
16
+ let inode = document.importNode($("#stats_engine")[0].content,true);
17
+ var iname = ename.replace(/[^a-z0-9A-Z]/g,'-').replace(/-$/,'')
18
+ $('.stats_title',inode).text($('.stats_title',inode).text() + ename)
19
+ $('.stats_plot',inode).attr('id','resource_utilization_plot_'+iname)
20
+ $('.stats_text',inode).attr('id','resource_utilization_text_'+iname)
21
+
22
+ $('#resources').append(inode)
23
+
24
+ resource_update(ename);
25
+
26
+ var trace1 = {
27
+ y: Array(value_count).fill(0),
28
+ type: 'scatter',
29
+ name: '% CPU'
30
+ };
31
+
32
+ var trace2 = {
33
+ y: Array(value_count).fill(0),
34
+ type: 'scatter',
35
+ name: '% Mem Used'
36
+ };
37
+
38
+ var layout = {
39
+ margin: {t:0,r:0,b:0,l:20},
40
+ height: 200,
41
+ width: 700,
42
+ yaxis: {
43
+ range: [-5, 105]
44
+ },
45
+ xaxis: {
46
+ showticklabels: false,
47
+ fixedrange: true
48
+ }
49
+ };
50
+
51
+ var data = [trace1, trace2];
52
+
53
+ Plotly.newPlot('resource_utilization_plot_' + iname, data, layout, {displayModeBar: false});
54
+ }
55
+
56
+ function instance_change(d) {
57
+ const ename = d.engine
58
+ const iname = d.engine.replace(/[^a-z0-9A-Z]/g,'-').replace(/-$/,'')
59
+
60
+ if (d.state == "ready") {
61
+ if ($('[data-id=' + d.uuid + ']').length > 0) {
62
+ if ($('[data-id=' + d.uuid + ']').attr('data-parent') != parent) {
63
+ $('[data-id=' + d.uuid + ']').remove()
64
+ instance_add(iname,d.uuid,d.url,d.name,d.state,d.author,0,0,d.parent)
65
+ } else {
66
+ instance_upd(d.uuid,d.name,d.state,d.author,0,0,d.parent)
67
+ }
68
+ } else {
69
+ instance_add(iname,d.uuid,d.url,d.name,d.state,d.author,0,0,d.parent)
70
+ }
71
+ } else if (d.state == 'abandoned' || d.state == 'finished') {
72
+ if ($('tr.sub[data-id=' + d.uuid + '] > td > table > tr').length > 0) {
73
+ $('tr.text[data-id=' + d.uuid + ']').replaceWith($('tr.sub[data-id=' + d.uuid + '] > td > table > tr'))
74
+ }
75
+ $('[data-id=' + d.uuid + ']').remove()
76
+ instances_striping(iname)
77
+ } else {
78
+ if ($('tr.sub[data-id=' + d.uuid + ']').attr('data-parent') != d.parent) {
79
+ $('[data-id=' + d.uuid + ']').remove()
80
+ instance_add(iname,d.uuid,d.url,d.name,d.state,d.author,0,0,d.parent)
81
+ } else {
82
+ instance_upd(d.uuid,d.name,d.state,d.author,0,0,d.parent)
83
+ }
84
+ }
85
+ }
86
+
87
+ function instance_upd(uuid,name,state,author,cpu,mem,parent) {
88
+ if (name != "") {
89
+ $('[data-id=' + uuid + '] > .name a').text(name)
90
+ }
91
+ $('[data-id=' + uuid + '] > .state span.value').text(state)
92
+ $('[data-id=' + uuid + '] > .state').attr('data-state',state)
93
+ if (author != "") {
94
+ $('[data-id=' + uuid + '] > .author').text(author)
95
+ }
96
+ instance_res(uuid,cpu,mem)
97
+ }
98
+ function instance_res(uuid,cpu,mem) {
99
+ $('[data-id=' + uuid + '] > .cpu').text($.sprintf('%05.2f',cpu))
100
+ $('[data-id=' + uuid + '] > .mem').text($.sprintf('%05.2f',mem))
101
+ }
102
+ function instance_add(iname,uuid,url,name,state,author,cpu,mem,parent) {
103
+ let inode = document.importNode($("#stats_instance")[0].content,true);
104
+ $('.sub',inode).attr('id',uuid)
105
+ $('.sub',inode).attr('data-id',uuid)
106
+ $('.sub',inode).attr('data-parent',parent)
107
+ $('.text',inode).attr('data-id',uuid)
108
+ $('.text',inode).attr('data-url',url)
109
+ $('.name a',inode).attr('href','server/dash/show?url=' + url)
110
+ $('.num span',inode).text(url.split(/[\\/]/).pop())
111
+ if (name != "") {
112
+ $('.name a',inode).text(name)
113
+ }
114
+ $('.state span.value',inode).text(state)
115
+ $('.state',inode).attr('data-state',state)
116
+ if (author != "") {
117
+ $('.author',inode).text(author)
118
+ }
119
+ $('.cpu',inode).text($.sprintf('%05.2f',cpu))
120
+ $('.mem',inode).text($.sprintf('%05.2f',mem))
121
+ if (parent == "") {
122
+ $('#instances_' + iname).append(inode)
123
+ } else {
124
+ $('#' + parent + ' > td > table').append(inode)
125
+ }
126
+ instances_striping(iname)
127
+ }
128
+
129
+ function instances_striping(iname) {
130
+ let even = true
131
+ $('#instances_' + iname + ' tr.text').removeClass('even')
132
+ $('#instances_' + iname + ' tr.text').each((i,e)=>{
133
+ if (even) {
134
+ $(e).addClass('even')
135
+ }
136
+ even = (even == true ? false : true)
137
+ })
138
+ }
139
+
140
+ function instances_init(ename) {
141
+ const iname = ename.replace(/[^a-z0-9A-Z]/g,'-').replace(/-$/,'')
142
+ let inode = document.importNode($("#stats_instances")[0].content,true);
143
+ $('.stats_title',inode).text($('.stats_title',inode).text() + ename)
144
+ $('table',inode).attr('id','instances_'+iname)
145
+ $('#instances').append(inode)
146
+ $.ajax({
147
+ type: "GET",
148
+ url: 'server/dash/instances',
149
+ data: { engine: ename },
150
+ success: (result) => {
151
+ $('instance',result).each((i,ele)=>{
152
+ const e = $(ele);
153
+ instance_add(iname,e.attr('uuid'),e.attr('url'),e.attr('name'),e.attr('state'),e.attr('author'),e.attr('cpu'),e.attr('mem'),e.attr('parent'))
154
+ })
155
+ }
156
+ })
157
+ }
158
+
159
+ function resource_paint(iname,data,count) {
160
+ count[iname]++
161
+ Plotly.extendTraces('resource_utilization_plot_' + iname, {y: [[data.cpu_usage], [(data.mem_total-data.mem_available)/data.mem_total * 100]]}, [0,1])
162
+ Plotly.relayout('resource_utilization_plot_' + iname, {
163
+ xaxis: {
164
+ range: [count[iname]-value_count,count[iname]],
165
+ showticklabels: false,
166
+ fixedrange: true
167
+ }
168
+ });
169
+ }
170
+
171
+ function stats_init() {
172
+ let es = new EventSource('server/dash/events/');
173
+ let count = {};
174
+ es.onopen = function() {
175
+ console.log('stats open');
176
+ };
177
+ es.onmessage = function(e) {
178
+ let data = JSON.parse(e.data)
179
+ const iname = data.engine.replace(/[^a-z0-9A-Z]/g,'-').replace(/-$/,'')
180
+ if ($('#instances').length > 0) {
181
+ if ($('#instances_' + iname).length == 0) {
182
+ instances_init(data.engine);
183
+ }
184
+ }
185
+ if (data.topic == "node" && data.event == "resource_utilization") {
186
+ if ($('#resources').length > 0) {
187
+ if ($('#resource_utilization_plot_' + iname).length == 0) {
188
+ resource_add(data.engine);
189
+ count[iname] = value_count;
190
+ }
191
+ resource_paint(iname,data,count)
192
+ }
193
+ } else if (data.topic == "state" && data.event == "change") {
194
+ if ($('#resources').length > 0) {
195
+ resource_update(data.engine)
196
+ }
197
+ if ($('#instances').length > 0) {
198
+ instance_change(data)
199
+ }
200
+ } else if (data.topic == "status" && data.event == "resource_utilization") {
201
+ if ($('#instances').length > 0) {
202
+ instance_res(data.uuid,data.cpu,data.mem)
203
+ }
204
+ } else {
205
+ console.log(data);
206
+ }
207
+ };
208
+ es.onerror = function() {
209
+ console.log('stats error');
210
+ }
211
+ }
212
+
213
+ $(document).ready(function() {
214
+ stats_init();
215
+ $('#instances').on('click','.abandon',function(e){
216
+ const par = $(e.target).parents('[data-url]').first()
217
+ $.ajax({
218
+ type: "PUT",
219
+ url: 'server/dash/abandon',
220
+ data: { url: par.attr('data-url') }
221
+ })
222
+ })
223
+ });
data/ui/resources.html ADDED
@@ -0,0 +1,91 @@
1
+ <!--
2
+ This file is part of CPEE-MODEL-MANAGEMENT.
3
+
4
+ CPEE-MODEL-MANAGEMENT is free software: you can redistribute it and/or
5
+ modify it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or (at your
7
+ option) any later version.
8
+
9
+ CPEE-MODEL-MANAGEMENT is distributed in the hope that it will be useful, but
10
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
+ more details.
13
+
14
+ You should have received a copy of the GNU General Public License along with
15
+ CPEE-MODEL-MANAGEMENT (file LICENSE in the main directory). If not, see
16
+ <http://www.gnu.org/licenses/>.
17
+ -->
18
+
19
+ <!DOCTYPE html>
20
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
21
+ <head>
22
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
23
+ <title>Resources</title>
24
+
25
+ <!-- libs, do not modify. When local than load local libs. -->
26
+ <script type="text/javascript" src="/js_libs/jquery.min.js"></script>
27
+ <script type="text/javascript" src="/js_libs/jquery.browser.js"></script>
28
+ <script type="text/javascript" src="/js_libs/jquery.svg.min.js"></script>
29
+ <script type="text/javascript" src="/js_libs/jquery.svgdom.min.js"></script>
30
+ <script type="text/javascript" src="/js_libs/vkbeautify.js"></script>
31
+ <script type="text/javascript" src="/js_libs/util.js"></script>
32
+ <script type="text/javascript" src="/js_libs/printf.js"></script>
33
+ <script type="text/javascript" src="/js_libs/strftime.min.js"></script>
34
+ <script type="text/javascript" src="/js_libs/parsequery.js"></script>
35
+ <script type="text/javascript" src="/js_libs/underscore.min.js"></script>
36
+ <script type="text/javascript" src="/js_libs/jquery.caret.min.js"></script>
37
+ <script type="text/javascript" src="/js_libs/jquery.cookie.js"></script>
38
+ <script type="text/javascript" src="/js_libs/plotly.min.js"></script>
39
+
40
+ <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
41
+
42
+ <script type="text/javascript" src="/js_libs/relaxngui.js"></script>
43
+
44
+ <script type="text/javascript" src="/js_libs/uidash.js"></script>
45
+ <script type="text/javascript" src="/js_libs/custommenu.js"></script>
46
+
47
+ <link rel="stylesheet" href="/js_libs/custommenu.css" type="text/css"/>
48
+ <link rel="stylesheet" href="/js_libs/uidash.css" type="text/css"/>
49
+
50
+ <link rel="stylesheet" href="/global_ui/ui.css" type="text/css"/>
51
+
52
+ <link rel="stylesheet" href="/js_libs/relaxngui.css" type="text/css"/>
53
+
54
+ <!-- custom stuff, play arround -->
55
+ <link rel="stylesheet" href="css/stats.css" type="text/css"/>
56
+ <link rel="stylesheet" href="css/stats_standalone.css" type="text/css"/>
57
+ <script type="text/javascript" src="js/stats.js"></script>
58
+ </head>
59
+ <body is="x-ui-">
60
+ <p>
61
+ Show statistics about instances per server, and metrics about the health of the environment.
62
+ </p>
63
+ <template id="stats_engine">
64
+ <h1 class="stats_title">Engine: </h1>
65
+ <div class="stats_plot"></div>
66
+ <div class="stats_text">
67
+ <table>
68
+ <tbody>
69
+ <tr>
70
+ <td>Total Instances <strong>Created</strong> / <strong>Finished</strong> / <strong>Abandoned</strong>:</td>
71
+ <td class='total_created'></td>
72
+ <td>/</td>
73
+ <td class='total_finished'></td>
74
+ <td>/</td>
75
+ <td class='total_abandoned'></td>
76
+ </tr>
77
+ <tr>
78
+ <td>Instances Currently <strong>Ready</strong> / <strong>Running</strong> / <strong>Stopped</strong>:</td>
79
+ <td class='current_ready'></td>
80
+ <td>/</td>
81
+ <td class='current_running'></td>
82
+ <td>/</td>
83
+ <td class='current_stopped'></td>
84
+ </tr>
85
+ </tbody>
86
+ </table>
87
+ </div>
88
+ </template>
89
+ <div id='resources'></div>
90
+ </body>
91
+ </html>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpee-model-management
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.18
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juergen eTM Mangler
8
8
  autorequire:
9
9
  bindir: tools
10
10
  cert_chain: []
11
- date: 2021-10-28 00:00:00.000000000 Z
11
+ date: 2022-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: riddl
@@ -73,6 +73,7 @@ files:
73
73
  - cpee-model-management.gemspec
74
74
  - lib/cpee-model-management/commit.rb
75
75
  - lib/cpee-model-management/implementation.rb
76
+ - lib/cpee-model-management/implementation.xml
76
77
  - lib/cpee-model-management/moma.xml
77
78
  - lib/cpee-model-management/stages
78
79
  - server/model.xml
@@ -81,8 +82,13 @@ files:
81
82
  - server/testset.xml
82
83
  - tools/cpee-moma
83
84
  - ui/css/design.css
85
+ - ui/css/stats.css
86
+ - ui/css/stats_standalone.css
84
87
  - ui/index.html
88
+ - ui/instances.html
85
89
  - ui/js/design.js
90
+ - ui/js/stats.js
91
+ - ui/resources.html
86
92
  homepage: http://cpee.org/
87
93
  licenses:
88
94
  - LGPL-3.0
@@ -102,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
108
  - !ruby/object:Gem::Version
103
109
  version: '0'
104
110
  requirements: []
105
- rubygems_version: 3.2.22
111
+ rubygems_version: 3.3.7
106
112
  signing_key:
107
113
  specification_version: 4
108
114
  summary: "(Lifecycle) manage your process models in a directory or git repo."