Commit 09b07ed6 by Szabolcs Gelencser

implement vnc

parent 9fb467a7
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
<project version="4"> <project version="4">
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="1fbec8af-5a7c-40f9-b994-83ac07d1ae1d" name="Default" comment=""> <list default="true" id="1fbec8af-5a7c-40f9-b994-83ac07d1ae1d" name="Default" comment="">
<change beforePath="$PROJECT_DIR$/circle/network/templates/network/vxlan-create.html" afterPath="$PROJECT_DIR$/circle/network/templates/network/vxlan-create.html" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
<change beforePath="$PROJECT_DIR$/circle/network/templates/network/vxlan-edit.html" afterPath="$PROJECT_DIR$/circle/network/templates/network/vxlan-edit.html" /> <change beforePath="$PROJECT_DIR$/circle/circle/settings/local.py" afterPath="$PROJECT_DIR$/circle/circle/settings/local.py" />
<change beforePath="$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-detail/console.html" afterPath="$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-detail/console.html" />
<change beforePath="$PROJECT_DIR$/circle/dashboard/views/vm.py" afterPath="$PROJECT_DIR$/circle/dashboard/views/vm.py" />
</list> </list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" /> <option name="TRACKING_ENABLED" value="true" />
...@@ -29,34 +31,36 @@ ...@@ -29,34 +31,36 @@
</component> </component>
<component name="FileEditorManager"> <component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300"> <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="forms.py" pinned="false" current-in-tab="false"> <file leaf-file-name="console.html" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/circle/network/forms.py"> <entry file="file://$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-detail/console.html">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="465"> <state relative-caret-position="374">
<caret line="381" column="0" lean-forward="false" selection-start-line="381" selection-start-column="0" selection-end-line="381" selection-end-column="0" /> <caret line="43" column="65" lean-forward="false" selection-start-line="43" selection-start-column="65" selection-end-line="43" selection-end-column="65" />
<folding> <folding>
<element signature="e#732#775#0" expanded="true" /> <element signature="n#style#0;n#iframe#0;n#!!top" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file leaf-file-name="vxlan-edit.html" pinned="false" current-in-tab="true"> <file leaf-file-name="local.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/circle/network/templates/network/vxlan-edit.html"> <entry file="file://$PROJECT_DIR$/circle/circle/settings/local.py">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="391"> <state relative-caret-position="151">
<caret line="23" column="0" lean-forward="false" selection-start-line="23" selection-start-column="0" selection-end-line="23" selection-end-column="0" /> <caret line="34" column="20" lean-forward="true" selection-start-line="34" selection-start-column="20" selection-end-line="34" selection-end-column="20" />
<folding /> <folding />
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
<file leaf-file-name="vm-plain-image-create.html" pinned="false" current-in-tab="false"> <file leaf-file-name="vm.py" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-plain-image-create.html"> <entry file="file://$PROJECT_DIR$/circle/dashboard/views/vm.py">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="119"> <state relative-caret-position="450">
<caret line="7" column="2" lean-forward="false" selection-start-line="7" selection-start-column="2" selection-end-line="16" selection-end-column="9" /> <caret line="126" column="28" lean-forward="false" selection-start-line="126" selection-start-column="28" selection-end-line="126" selection-end-column="28" />
<folding /> <folding>
<element signature="e#40144#41315#0" expanded="false" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
...@@ -73,8 +77,6 @@ ...@@ -73,8 +77,6 @@
</component> </component>
<component name="FindInProjectRecents"> <component name="FindInProjectRecents">
<findStrings> <findStrings>
<find>class</find>
<find>vmcreate</find>
<find>priority_choices</find> <find>priority_choices</find>
<find>plain</find> <find>plain</find>
<find>asd</find> <find>asd</find>
...@@ -103,6 +105,8 @@ ...@@ -103,6 +105,8 @@
<find>vxlancrea</find> <find>vxlancrea</find>
<find>forms</find> <find>forms</find>
<find>create</find> <find>create</find>
<find>vnc</find>
<find>c</find>
</findStrings> </findStrings>
<replaceStrings> <replaceStrings>
<replace>'ACTIVE'</replace> <replace>'ACTIVE'</replace>
...@@ -116,8 +120,6 @@ ...@@ -116,8 +120,6 @@
<component name="IdeDocumentHistory"> <component name="IdeDocumentHistory">
<option name="CHANGED_PATHS"> <option name="CHANGED_PATHS">
<list> <list>
<option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/index-vm.html" />
<option value="$PROJECT_DIR$/circle/dashboard/templates/base.html" />
<option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/base.html" /> <option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/base.html" />
<option value="$PROJECT_DIR$/circle/vm/managers/os_instance_manager.py" /> <option value="$PROJECT_DIR$/circle/vm/managers/os_instance_manager.py" />
<option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-detail/home.html" /> <option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-detail/home.html" />
...@@ -152,21 +154,23 @@ ...@@ -152,21 +154,23 @@
<option value="$PROJECT_DIR$/circle/openstack_api/policy.py" /> <option value="$PROJECT_DIR$/circle/openstack_api/policy.py" />
<option value="$PROJECT_DIR$/circle/dashboard/forms.py" /> <option value="$PROJECT_DIR$/circle/dashboard/forms.py" />
<option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-plain-image-create.html" /> <option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-plain-image-create.html" />
<option value="$PROJECT_DIR$/circle/dashboard/views/vm.py" />
<option value="$PROJECT_DIR$/circle/vm/models/instance.py" /> <option value="$PROJECT_DIR$/circle/vm/models/instance.py" />
<option value="$PROJECT_DIR$/circle/dashboard/views/util.py" /> <option value="$PROJECT_DIR$/circle/dashboard/views/util.py" />
<option value="$PROJECT_DIR$/circle/request/urls.py" /> <option value="$PROJECT_DIR$/circle/request/urls.py" />
<option value="$PROJECT_DIR$/circle/dashboard/views/index.py" />
<option value="$PROJECT_DIR$/circle/network/models.py" /> <option value="$PROJECT_DIR$/circle/network/models.py" />
<option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/index-vxlans.html" /> <option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/index-vxlans.html" />
<option value="$PROJECT_DIR$/circle/openstack_api/base.py" /> <option value="$PROJECT_DIR$/circle/openstack_api/base.py" />
<option value="$PROJECT_DIR$/circle/dashboard/urls.py" /> <option value="$PROJECT_DIR$/circle/dashboard/urls.py" />
<option value="$PROJECT_DIR$/circle/network/urls.py" /> <option value="$PROJECT_DIR$/circle/network/urls.py" />
<option value="$PROJECT_DIR$/circle/openstack_api/nova.py" />
<option value="$PROJECT_DIR$/circle/network/forms.py" /> <option value="$PROJECT_DIR$/circle/network/forms.py" />
<option value="$PROJECT_DIR$/circle/network/views.py" /> <option value="$PROJECT_DIR$/circle/network/views.py" />
<option value="$PROJECT_DIR$/circle/network/templates/network/vxlan-create.html" /> <option value="$PROJECT_DIR$/circle/network/templates/network/vxlan-create.html" />
<option value="$PROJECT_DIR$/circle/network/templates/network/vxlan-edit.html" /> <option value="$PROJECT_DIR$/circle/network/templates/network/vxlan-edit.html" />
<option value="$PROJECT_DIR$/circle/openstack_api/nova.py" />
<option value="$PROJECT_DIR$/circle/dashboard/views/index.py" />
<option value="$PROJECT_DIR$/circle/dashboard/views/vm.py" />
<option value="$PROJECT_DIR$/circle/circle/settings/local.py" />
<option value="$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-detail/console.html" />
</list> </list>
</option> </option>
</component> </component>
...@@ -236,13 +240,31 @@ ...@@ -236,13 +240,31 @@
<item name="cloud" type="b2602c69:ProjectViewProjectNode" /> <item name="cloud" type="b2602c69:ProjectViewProjectNode" />
<item name="cloud" type="462c0819:PsiDirectoryNode" /> <item name="cloud" type="462c0819:PsiDirectoryNode" />
<item name="circle" type="462c0819:PsiDirectoryNode" /> <item name="circle" type="462c0819:PsiDirectoryNode" />
<item name="network" type="462c0819:PsiDirectoryNode" /> <item name="dashboard" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cloud" type="b2602c69:ProjectViewProjectNode" />
<item name="cloud" type="462c0819:PsiDirectoryNode" />
<item name="circle" type="462c0819:PsiDirectoryNode" />
<item name="dashboard" type="462c0819:PsiDirectoryNode" />
<item name="templates" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cloud" type="b2602c69:ProjectViewProjectNode" />
<item name="cloud" type="462c0819:PsiDirectoryNode" />
<item name="circle" type="462c0819:PsiDirectoryNode" />
<item name="dashboard" type="462c0819:PsiDirectoryNode" />
<item name="templates" type="462c0819:PsiDirectoryNode" />
<item name="dashboard" type="462c0819:PsiDirectoryNode" />
</path> </path>
<path> <path>
<item name="cloud" type="b2602c69:ProjectViewProjectNode" /> <item name="cloud" type="b2602c69:ProjectViewProjectNode" />
<item name="cloud" type="462c0819:PsiDirectoryNode" /> <item name="cloud" type="462c0819:PsiDirectoryNode" />
<item name="circle" type="462c0819:PsiDirectoryNode" /> <item name="circle" type="462c0819:PsiDirectoryNode" />
<item name="openstack_api" type="462c0819:PsiDirectoryNode" /> <item name="dashboard" type="462c0819:PsiDirectoryNode" />
<item name="templates" type="462c0819:PsiDirectoryNode" />
<item name="dashboard" type="462c0819:PsiDirectoryNode" />
<item name="vm-detail" type="462c0819:PsiDirectoryNode" />
</path> </path>
</expand> </expand>
<select /> <select />
...@@ -257,7 +279,7 @@ ...@@ -257,7 +279,7 @@
<property name="settings.editor.selected.configurable" value="preferences.sourceCode.HTML" /> <property name="settings.editor.selected.configurable" value="preferences.sourceCode.HTML" />
<property name="NewWatcherDialog.advanced.open" value="true" /> <property name="NewWatcherDialog.advanced.open" value="true" />
<property name="DefaultHtmlFileTemplate" value="HTML File" /> <property name="DefaultHtmlFileTemplate" value="HTML File" />
<property name="SearchEverywhereHistoryKey" value="plain&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/vm-plain-image-create.html&#10;forms&#9;null&#9;null&#10;vxlanform&#9;null&#9;null&#10;instanc&#9;FILE&#9;file:///home/h3yduck/cloud/circle/vm/models/instance.py&#10;index&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/views/index.py&#10;index-vxla&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/index-vxlans.html&#10;instance&#9;FILE&#9;file:///home/h3yduck/cloud/circle/vm/models/instance.py&#10;_vm-c&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/_vm-create-1.html&#10;vmcrea&#9;null&#9;null&#10;loginV&#9;null&#9;null&#10;index.html&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/index.html&#10;sleep&#9;null&#9;null&#10;Deploy&#9;null&#9;null&#10;Instance&#9;null&#9;null&#10;Vmdeta&#9;null&#9;null&#10;list_from&#9;null&#9;null&#10;aclupda&#9;null&#9;null&#10;base.htm&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/base.html&#10;method&#9;ACTION&#9;GoToMenuEx&#10;base.ht&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/base.html&#10;base.html&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/base.html&#10;index.py&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/views/index.py&#10;index.htm&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/index.html&#10;server&#9;null&#9;null&#10;Disk&#9;null&#9;null" /> <property name="SearchEverywhereHistoryKey" value="local&#9;null&#9;null&#10;vmdeta&#9;null&#9;null&#10;index&#9;null&#9;null&#10;vnc&#9;null&#9;null&#10;plain&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/vm-plain-image-create.html&#10;forms&#9;null&#9;null&#10;vxlanform&#9;null&#9;null&#10;instanc&#9;FILE&#9;file:///home/h3yduck/cloud/circle/vm/models/instance.py&#10;index-vxla&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/index-vxlans.html&#10;instance&#9;FILE&#9;file:///home/h3yduck/cloud/circle/vm/models/instance.py&#10;_vm-c&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/_vm-create-1.html&#10;vmcrea&#9;null&#9;null&#10;loginV&#9;null&#9;null&#10;index.html&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/index.html&#10;sleep&#9;null&#9;null&#10;Deploy&#9;null&#9;null&#10;Instance&#9;null&#9;null&#10;Vmdeta&#9;null&#9;null&#10;list_from&#9;null&#9;null&#10;aclupda&#9;null&#9;null&#10;base.htm&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/base.html&#10;method&#9;ACTION&#9;GoToMenuEx&#10;base.ht&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/base.html&#10;base.html&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/base.html&#10;index.py&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/views/index.py&#10;index.htm&#9;FILE&#9;file:///home/h3yduck/cloud/circle/dashboard/templates/dashboard/index.html&#10;server&#9;null&#9;null&#10;Disk&#9;null&#9;null" />
</component> </component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS"> <key name="MoveFile.RECENT_KEYS">
...@@ -276,7 +298,26 @@ ...@@ -276,7 +298,26 @@
</list> </list>
</option> </option>
</component> </component>
<component name="RunManager"> <component name="RunManager" selected="Python.index">
<configuration name="index" type="PythonConfigurationType" factoryName="Python" temporary="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/circle/dashboard/views" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="cloud" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/circle/dashboard/views/index.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
</configuration>
<configuration name="circlestack" type="Python.DjangoServer" factoryName="Django server"> <configuration name="circlestack" type="Python.DjangoServer" factoryName="Django server">
<option name="INTERPRETER_OPTIONS" value="" /> <option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" /> <option name="PARENT_ENVS" value="true" />
...@@ -300,6 +341,15 @@ ...@@ -300,6 +341,15 @@
<option name="useCustomRunCommand" value="false" /> <option name="useCustomRunCommand" value="false" />
<option name="customRunCommand" value="" /> <option name="customRunCommand" value="" />
</configuration> </configuration>
<list size="2">
<item index="0" class="java.lang.String" itemvalue="Django server.circlestack" />
<item index="1" class="java.lang.String" itemvalue="Python.index" />
</list>
<recent_temporary>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="Python.index" />
</list>
</recent_temporary>
</component> </component>
<component name="ShelveChangesManager" show_recycled="false"> <component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" /> <option name="remove_strategy" value="false" />
...@@ -332,11 +382,12 @@ ...@@ -332,11 +382,12 @@
<layout> <layout>
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32980973" sideWeight="0.4978701" order="6" side_tool="false" content_ui="tabs" /> <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32980973" sideWeight="0.4978701" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.327818" sideWeight="0.5021299" order="7" side_tool="true" content_ui="tabs" /> <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.327818" sideWeight="0.5021299" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32875264" sideWeight="0.4978701" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3280757" sideWeight="0.4978701" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3280757" sideWeight="0.5234139" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3280757" sideWeight="0.5234139" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.43023255" sideWeight="0.43610224" order="7" side_tool="true" content_ui="tabs" /> <window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.43023255" sideWeight="0.43610224" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Coverage" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3280757" sideWeight="0.4765861" order="7" side_tool="true" content_ui="tabs" /> <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3280757" sideWeight="0.4765861" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.18504532" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.23036253" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Docker" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" /> <window_info id="Docker" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" />
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="SciView" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="SciView" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
...@@ -425,7 +476,7 @@ ...@@ -425,7 +476,7 @@
</properties> </properties>
</breakpoint> </breakpoint>
</default-breakpoints> </default-breakpoints>
<option name="time" value="161" /> <option name="time" value="163" />
</breakpoint-manager> </breakpoint-manager>
<watches-manager /> <watches-manager />
</component> </component>
...@@ -458,68 +509,53 @@ ...@@ -458,68 +509,53 @@
</expressions> </expressions>
<expressions id="evaluateExpression"> <expressions id="evaluateExpression">
<expression> <expression>
<expression-string>form.cleaned_data</expression-string> <expression-string>openstack_api.nova.server_vnc_console(self.request, instance.os_server_id)</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>form['name']</expression-string> <expression-string>openstack_api.nova.server_vnc_console(self.request)</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>form.name</expression-string> <expression-string>instance</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>form.fields.name</expression-string> <expression-string>form.cleaned_data</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>form.fields['name']</expression-string> <expression-string>form['name']</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>context[u'object'].id</expression-string> <expression-string>form.name</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>self.get_object().pk</expression-string> <expression-string>form.fields.name</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>self.get_object()</expression-string> <expression-string>form.fields['name']</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
<expression> <expression>
<expression-string>request.POST.get(&quot;network&quot;)</expression-string> <expression-string>context[u'object'].id</expression-string>
<language-id>Python</language-id> <language-id>Python</language-id>
<evaluation-mode>EXPRESSION</evaluation-mode> <evaluation-mode>EXPRESSION</evaluation-mode>
</expression> </expression>
</expressions> </expressions>
</component> </component>
<component name="editorHistoryManager"> <component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/circle/templates/registration/login.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="28" lean-forward="false" selection-start-line="0" selection-start-column="28" selection-end-line="0" selection-end-column="28" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/views/user.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="272">
<caret line="105" column="0" lean-forward="true" selection-start-line="105" selection-start-column="0" selection-end-line="105" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/templates/dashboard/index.html"> <entry file="file://$PROJECT_DIR$/circle/dashboard/templates/dashboard/index.html">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="306"> <state relative-caret-position="306">
...@@ -804,24 +840,6 @@ ...@@ -804,24 +840,6 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/views/index.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="232">
<caret line="108" column="46" lean-forward="false" selection-start-line="108" selection-start-column="46" selection-end-line="108" selection-end-column="46" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/views/vm.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="257">
<caret line="110" column="0" lean-forward="true" selection-start-line="110" selection-start-column="0" selection-end-line="110" selection-end-column="0" />
<folding>
<element signature="e#40141#41312#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/openstack_api/base.py"> <entry file="file://$PROJECT_DIR$/circle/openstack_api/base.py">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="126"> <state relative-caret-position="126">
...@@ -830,14 +848,6 @@ ...@@ -830,14 +848,6 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/circle/openstack_api/nova.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="101">
<caret line="510" column="58" lean-forward="false" selection-start-line="510" selection-start-column="58" selection-end-line="510" selection-end-column="58" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/.virtualenvs/cloud/local/lib/python2.7/site-packages/django/views/generic/edit.py"> <entry file="file://$USER_HOME$/.virtualenvs/cloud/local/lib/python2.7/site-packages/django/views/generic/edit.py">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="202"> <state relative-caret-position="202">
...@@ -864,14 +874,6 @@ ...@@ -864,14 +874,6 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-plain-image-create.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="119">
<caret line="7" column="2" lean-forward="false" selection-start-line="7" selection-start-column="2" selection-end-line="16" selection-end-column="9" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/network/urls.py"> <entry file="file://$PROJECT_DIR$/circle/network/urls.py">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="227"> <state relative-caret-position="227">
...@@ -910,23 +912,75 @@ ...@@ -910,23 +912,75 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/circle/network/templates/network/vxlan-edit.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="272">
<caret line="16" column="24" lean-forward="true" selection-start-line="16" selection-start-column="24" selection-end-line="16" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-plain-image-create.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="119">
<caret line="7" column="2" lean-forward="false" selection-start-line="7" selection-start-column="2" selection-end-line="16" selection-end-column="9" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/openstack_api/nova.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="202">
<caret line="70" column="6" lean-forward="false" selection-start-line="70" selection-start-column="6" selection-end-line="70" selection-end-column="6" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/network/forms.py"> <entry file="file://$PROJECT_DIR$/circle/network/forms.py">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="465"> <state relative-caret-position="210">
<caret line="381" column="0" lean-forward="false" selection-start-line="381" selection-start-column="0" selection-end-line="381" selection-end-column="0" /> <caret line="366" column="24" lean-forward="true" selection-start-line="366" selection-start-column="24" selection-end-line="366" selection-end-column="24" />
<folding> <folding>
<element signature="e#732#775#0" expanded="true" /> <element signature="e#732#775#0" expanded="true" />
</folding> </folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/circle/network/templates/network/vxlan-edit.html"> <entry file="file://$PROJECT_DIR$/circle/dashboard/views/index.py">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="391"> <state relative-caret-position="95">
<caret line="23" column="0" lean-forward="false" selection-start-line="23" selection-start-column="0" selection-end-line="23" selection-end-column="0" /> <caret line="129" column="0" lean-forward="true" selection-start-line="129" selection-start-column="0" selection-end-line="129" selection-end-column="0" />
<folding /> <folding />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/views/vm.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="450">
<caret line="126" column="28" lean-forward="false" selection-start-line="126" selection-start-column="28" selection-end-line="126" selection-end-column="28" />
<folding>
<element signature="e#40144#41315#0" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/circle/settings/local.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="151">
<caret line="34" column="20" lean-forward="true" selection-start-line="34" selection-start-column="20" selection-end-line="34" selection-end-column="20" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/circle/dashboard/templates/dashboard/vm-detail/console.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="374">
<caret line="43" column="65" lean-forward="false" selection-start-line="43" selection-start-column="65" selection-end-line="43" selection-end-column="65" />
<folding>
<element signature="n#style#0;n#iframe#0;n#!!top" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component> </component>
</project> </project>
\ No newline at end of file
...@@ -37,6 +37,7 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') ...@@ -37,6 +37,7 @@ SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
########## END EMAIL CONFIGURATION ########## END EMAIL CONFIGURATION
CORS_ORIGIN_ALLOW_ALL = True
########## DATABASE CONFIGURATION ########## DATABASE CONFIGURATION
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases # See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
......
/**
* Licensed 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.
*/
/* global Hogan */
/* Namespace for core functionality related to Network Topology. */
horizon.flat_network_topology = {
model: null,
fa_globe_glyph: '\uf0ac',
fa_globe_glyph_width: 15,
svg:'#topology_canvas',
svg_container:'#flatTopologyCanvasContainer',
network_tmpl:{
small:'#topology_template > .network_container_small',
normal:'#topology_template > .network_container_normal'
},
router_tmpl: {
small:'#topology_template > .router_small',
normal:'#topology_template > .router_normal'
},
instance_tmpl: {
small:'#topology_template > .instance_small',
normal:'#topology_template > .instance_normal'
},
balloon_tmpl : null,
balloon_device_tmpl : null,
balloon_port_tmpl : null,
network_index: {},
balloon_id:null,
reload_duration: 10000,
draw_mode:'normal',
network_height : 0,
previous_message : null,
element_properties:{
normal:{
network_width:270,
network_min_height:500,
top_margin:80,
default_height:50,
margin:20,
device_x:98.5,
device_width:90,
port_margin:16,
port_height:6,
port_width:82,
port_text_margin:{x:6,y:-4},
texts_bg_y:32,
type_y:46,
balloon_margin:{x:12,y:-12}
},
small :{
network_width:100,
network_min_height:400,
top_margin:50,
default_height:20,
margin:30,
device_x:47.5,
device_width:20,
port_margin:5,
port_height:3,
port_width:32.5,
port_text_margin:{x:0,y:0},
texts_bg_y:0,
type_y:0,
balloon_margin:{x:12,y:-30}
},
cidr_margin:5,
device_name_max_size:9,
device_name_suffix:'..'
},
init:function() {
var self = this;
self.$container = $(self.svg_container);
self.$loading_template = horizon.networktopologyloader.setup_loader($(self.$container));
if($('#networktopology').length === 0) {
return;
}
self.color = d3.scale.category10();
self.balloon_tmpl = Hogan.compile($('#balloon_container').html());
self.balloon_device_tmpl = Hogan.compile($('#balloon_device').html());
self.balloon_port_tmpl = Hogan.compile($('#balloon_port').html());
$(document)
.on('click', 'a.closeTopologyBalloon', function(e) {
e.preventDefault();
self.delete_balloon();
})
.on('click', '.topologyBalloon', function(e) {
e.stopPropagation();
})
.on('click', 'a.vnc_window', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
var vnc_window = window.open($(this).attr('href'), vnc_window, 'width=760,height=560');
self.delete_balloon();
})
.click(function(){
self.delete_balloon();
});
$('.toggle-view > .btn').click(function(){
self.draw_mode = $(this).data('value');
$('g.network').remove();
horizon.cookies.put('ntp_draw_mode',self.draw_mode);
self.data_convert();
});
self.$loading_template.show();
$('#networktopology').on('change', function() {
self.load_network_info();
});
// register for message notifications
//horizon.networktopologymessager.addMessageHandler(self.handleMessage, this);
},
/*handleMessage:function(message) {
// noop
},*/
load_network_info:function(){
var self = this;
self.model = horizon.networktopologyloader.model;
self.data_convert();
},
select_draw_mode:function() {
var self = this;
var draw_mode = 'normal';
try {
draw_mode = horizon.cookies.get('ntp_draw_mode');
}
catch(e) {
// if the cookie does not exist, angular-cookie passes "undefined" to
// JSON.parse which throws an exception
}
if (draw_mode && (draw_mode === 'normal' || draw_mode === 'small')) {
self.draw_mode = draw_mode;
} else {
if (self.model.networks.length *
self.element_properties.normal.network_width > $('#topologyCanvas').width()) {
self.draw_mode = 'small';
} else {
self.draw_mode = 'normal';
}
horizon.cookies.put('ntp_draw_mode',self.draw_mode);
}
$('.toggle-view > .btn').each(function(){
var $this = $(this);
if($this.data('value') === self.draw_mode) {
$this.addClass('active');
} else {
$this.removeClass('active');
}
});
},
data_convert:function() {
var self = this;
var model = self.model;
$.each(model.networks, function(index, network) {
self.network_index[network.id] = index;
});
self.select_draw_mode();
var element_properties = self.element_properties[self.draw_mode];
self.network_height = element_properties.top_margin;
$.each([
{model:model.routers, type:'router'},
{model:model.servers, type:'instance'}
], function(index, devices) {
var type = devices.type;
var model = devices.model;
$.each(model, function(index, device) {
device.type = type;
device.ports = self.select_port(device.id);
var hasports = device.ports.length > 0;
device.parent_network = (hasports) ? self.select_main_port(device.ports).network_id : self.model.networks[0].id;
var height = element_properties.port_margin*(device.ports.length - 1);
device.height = (self.draw_mode === 'normal' && height > element_properties.default_height) ? height : element_properties.default_height;
device.pos_y = self.network_height;
device.port_height = (self.draw_mode === 'small' && height > device.height) ? 1 : element_properties.port_height;
device.port_margin = (self.draw_mode === 'small' && height > device.height) ? device.height/device.ports.length : element_properties.port_margin;
self.network_height += device.height + element_properties.margin;
});
});
$.each(model.networks, function(index, network) {
network.devices = [];
$.each([model.routers, model.servers],function(index, devices) {
$.each(devices,function(index, device) {
if(network.id === device.parent_network) {
network.devices.push(device);
}
});
});
});
self.network_height += element_properties.top_margin;
self.network_height = (self.network_height > element_properties.network_min_height) ? self.network_height : element_properties.network_min_height;
self.draw_topology();
self.$loading_template.hide();
},
draw_topology:function() {
var self = this;
$(self.svg_container).removeClass('noinfo');
if (self.model.networks.length <= 0) {
$('g.network').remove();
$(self.svg_container).addClass('noinfo');
return;
}
var svg = d3.select(self.svg);
var element_properties = self.element_properties[self.draw_mode];
svg
.attr('width',self.model.networks.length*element_properties.network_width)
.attr('height',self.network_height);
var network = svg.selectAll('g.network')
.data(self.model.networks);
network.enter()
.append('g')
.attr('class','network')
.each(function(d){
this.appendChild(d3.select(self.network_tmpl[self.draw_mode]).node().cloneNode(true));
var $this = d3.select(this).select('.network-rect');
if (d.url) {
$this
.on('mouseover',function(){
$this.transition().style('fill', function() {
return d3.rgb(self.get_network_color(d.id)).brighter(0.5);
});
})
.on('mouseout',function(){
$this.transition().style('fill', function() {
return self.get_network_color(d.id);
});
})
.on('click',function(){
window.location.href = d.url;
});
} else {
$this.classed('nourl', true);
}
});
network
.attr('id',function(d) { return 'id_' + d.id; })
.attr('transform',function(d,i){
return 'translate(' + element_properties.network_width * i + ',' + 0 + ')';
})
.select('.network-rect')
.attr('height', function() { return self.network_height; })
.style('fill', function(d) { return self.get_network_color(d.id); });
network
.select('.network-name')
.attr('x', function() { return self.network_height/2; })
.text(function(d) { return d.name; });
network
.select('.network-cidr')
.attr('x', function(d) {
var padding = isExternalNetwork(d) ? self.fa_globe_glyph_width : 0;
return self.network_height - self.element_properties.cidr_margin -
padding;
})
.text(function(d) {
var cidr = $.map(d.subnets,function(n){
return n.cidr;
});
return cidr.join(', ');
});
function isExternalNetwork(d) {
return d['router:external'];
}
network
.select('.network-type')
.text(function(d) {
return isExternalNetwork(d) ? self.fa_globe_glyph : '';
})
.attr('x', function() {
return self.network_height - self.element_properties.cidr_margin;
});
$('[data-toggle="tooltip"]').tooltip({container: 'body'});
network.exit().remove();
var device = network.selectAll('g.device')
.data(function(d) { return d.devices; });
var device_enter = device.enter()
.append("g")
.attr('class','device')
.each(function(d){
var device_template = self[d.type + '_tmpl'][self.draw_mode];
this.appendChild(d3.select(device_template).node().cloneNode(true));
});
device_enter
.on('mouseenter',function(d){
var $this = $(this);
self.show_balloon(d,$this);
})
.on('click',function(){
d3.event.stopPropagation();
});
device
.attr('id',function(d) { return 'id_' + d.id; })
.attr('transform',function(d){
return 'translate(' + element_properties.device_x + ',' + d.pos_y + ')';
})
.select('.frame')
.attr('height',function(d) { return d.height; });
device
.select('.texts_bg')
.attr('y',function(d) {
return element_properties.texts_bg_y + d.height - element_properties.default_height;
});
device
.select('.type')
.attr('y',function(d) {
return element_properties.type_y + d.height - element_properties.default_height;
});
device
.select('.name')
.text(function(d) { return self.string_truncate(d.name); });
device.each(function(d) {
if (d.status === 'BUILD') {
d3.select(this).classed('loading',true);
} else if (d.task === 'deleting') {
d3.select(this).classed('loading',true);
if ('bl_' + d.id === self.balloon_id) {
self.delete_balloon();
}
} else {
d3.select(this).classed('loading',false);
if ('bl_' + d.id === self.balloon_id) {
var $this = $(this);
self.show_balloon(d,$this);
}
}
});
device.exit().each(function(d){
if ('bl_' + d.id === self.balloon_id) {
self.delete_balloon();
}
}).remove();
var port = device.select('g.ports')
.selectAll('g.port')
.data(function(d) { return d.ports; });
var port_enter = port.enter()
.append('g')
.attr('class','port')
.attr('id',function(d) { return 'id_' + d.id; });
port_enter
.append('line')
.attr('class','port_line');
port_enter
.append('text')
.attr('class','port_text');
device.select('g.ports').each(function(d){
this._portdata = {};
this._portdata.ports_length = d.ports.length;
this._portdata.parent_network = d.parent_network;
this._portdata.device_height = d.height;
this._portdata.port_height = d.port_height;
this._portdata.port_margin = d.port_margin;
this._portdata.left = 0;
this._portdata.right = 0;
$(this).mouseenter(function(e){
e.stopPropagation();
});
});
port.each(function(d){
var index_diff = self.get_network_index(this.parentNode._portdata.parent_network) -
self.get_network_index(d.network_id);
this._index_diff = index_diff = (index_diff >= 0)? ++index_diff : index_diff;
this._direction = (this._index_diff < 0)? 'right' : 'left';
this._index = this.parentNode._portdata[this._direction] ++;
});
port.attr('transform',function(){
var x = (this._direction === 'left') ? 0 : element_properties.device_width;
var ports_length = this.parentNode._portdata[this._direction];
var distance = this.parentNode._portdata.port_margin;
var y = (this.parentNode._portdata.device_height -
(ports_length -1)*distance)/2 + this._index*distance;
return 'translate(' + x + ',' + y + ')';
});
port
.select('.port_line')
.attr('stroke-width',function() {
return this.parentNode.parentNode._portdata.port_height;
})
.attr('stroke', function(d) {
return self.get_network_color(d.network_id);
})
.attr('x1',0).attr('y1',0).attr('y2',0)
.attr('x2',function() {
var parent = this.parentNode;
var width = (Math.abs(parent._index_diff) - 1)*element_properties.network_width +
element_properties.port_width;
return (parent._direction === 'left') ? -1*width : width;
});
port
.select('.port_text')
.attr('x',function() {
var parent = this.parentNode;
if (parent._direction === 'left') {
d3.select(this).classed('left',true);
return element_properties.port_text_margin.x*-1;
} else {
d3.select(this).classed('left',false);
return element_properties.port_text_margin.x;
}
})
.attr('y',function() {
return element_properties.port_text_margin.y;
})
.text(function(d) {
var ip_label = [];
$.each(d.fixed_ips, function() {
ip_label.push(this.ip_address);
});
return ip_label.join(',');
});
port.exit().remove();
},
get_network_color: function(network_id) {
return this.color(this.get_network_index(network_id));
},
get_network_index: function(network_id) {
return this.network_index[network_id];
},
select_port: function(device_id){
return $.map(this.model.ports,function(port){
if (port.device_id === device_id) {
return port;
}
});
},
select_main_port: function(ports){
var _self = this;
var main_port_index = 0;
var MAX_INT = 4294967295;
var min_port_length = MAX_INT;
$.each(ports, function(index, port){
var port_length = _self.sum_port_length(port.network_id, ports);
if(port_length < min_port_length){
min_port_length = port_length;
main_port_index = index;
}
});
return ports[main_port_index];
},
sum_port_length: function(network_id, ports){
var self = this;
var sum_port_length = 0;
var base_index = self.get_network_index(network_id);
$.each(ports, function(index, port){
sum_port_length += base_index - self.get_network_index(port.network_id);
});
return sum_port_length;
},
string_truncate: function(string) {
var self = this;
var str = string;
var max_size = self.element_properties.device_name_max_size;
var suffix = self.element_properties.device_name_suffix;
var bytes = 0;
for (var i = 0; i < str.length; i++) {
bytes += str.charCodeAt(i) <= 255 ? 1 : 2;
if (bytes > max_size) {
str = str.substr(0, i) + suffix;
break;
}
}
return str;
},
delete_device: function(device_type, device_id) {
var message = {id:device_id};
var target = device_type === 'instance' ? 'instance?id=' + device_id : device_type;
horizon.networktopologymessager.post_message(device_id, target, message, device_type, 'delete', data={});
},
delete_port: function(router_id, port_id, network_id) {
var message = {id:port_id};
var data = {router_id: router_id, network_id: network_id};
horizon.networktopologymessager.post_message(port_id, 'router/' + router_id + '/', message, 'port', 'delete', data);
},
show_balloon:function(d,element) {
var self = this;
var element_properties = self.element_properties[self.draw_mode];
if (self.balloon_id) {
self.delete_balloon();
}
var balloon_tmpl = self.balloon_tmpl;
var device_tmpl = self.balloon_device_tmpl;
var port_tmpl = self.balloon_port_tmpl;
var balloon_id = 'bl_' + d.id;
var ports = [];
$.each(d.ports,function(i, port){
var object = {};
object.id = port.id;
object.router_id = port.device_id;
object.url = port.url;
object.port_status = port.status;
object.port_status_class = (port.original_status === "ACTIVE")? 'active' : 'down';
var ip_address = '';
try {
ip_address = port.fixed_ips[0].ip_address;
}catch(e){
ip_address = gettext('None');
}
var device_owner = '';
try {
device_owner = port.device_owner.replace('network:','');
}catch(e){
device_owner = gettext('None');
}
var network_id = '';
try {
network_id = port.network_id;
}catch(e) {
network_id = gettext('None');
}
object.network_id = network_id;
object.ip_address = ip_address;
object.device_owner = device_owner;
object.is_interface = (
device_owner === 'router_interface' ||
device_owner === 'router_gateway' ||
device_owner === 'ha_router_replicated_interface'
);
// (device_owner === 'router_interface' || device_owner === 'router_gateway');
ports.push(object);
});
var html;
var html_data = {
balloon_id:balloon_id,
id:d.id,
url:d.url,
name:d.name,
type:d.type,
delete_label: gettext("Delete"),
status:d.status,
status_class:(d.original_status === "ACTIVE")? 'active' : 'down',
status_label: gettext("STATUS"),
id_label: gettext("ID"),
interfaces_label: gettext("Interfaces"),
delete_interface_label: gettext("Delete Interface"),
open_console_label: gettext("Open Console"),
view_details_label: gettext("View Details")
};
if (d.type === 'router') {
html_data.delete_label = gettext("Delete Router");
html_data.view_details_label = gettext("View Router Details");
html_data.port = ports;
html_data.add_interface_url = d.url + 'addinterface';
html_data.add_interface_label = gettext("Add Interface");
html = balloon_tmpl.render(html_data,{
table1:device_tmpl,
table2:(ports.length > 0) ? port_tmpl : null
});
} else if (d.type === 'instance') {
html_data.delete_label = gettext("Delete Instance");
html_data.view_details_label = gettext("View Instance Details");
html_data.console_id = d.id;
html_data.console = d.console;
html = balloon_tmpl.render(html_data,{
table1:device_tmpl
});
} else {
return;
}
$(self.svg_container).append(html);
var device_position = element.find('.frame');
var sidebar_width = $("#sidebar").width();
var navbar_height = $(".navbar").height();
var breadcrumb_height = $(".breadcrumb").outerHeight(true);
var pageheader_height = $(".page-header").outerHeight(true);
var launchbuttons_height = $(".launchButtons").height();
var height_offset = navbar_height + breadcrumb_height + pageheader_height + launchbuttons_height;
var device_offset = device_position.offset();
var x = Math.round(device_offset.left + element_properties.device_width + element_properties.balloon_margin.x - sidebar_width);
// 15 is magic pixel value that seems to make things line up
var y = Math.round(device_offset.top + element_properties.balloon_margin.y - height_offset + 15);
var $balloon = $('#' + balloon_id);
$balloon.css({
'left': '0px',
'top': y + 'px'
});
var balloon_width = $balloon.outerWidth();
var left_x = device_offset.left - balloon_width - element_properties.balloon_margin.x - sidebar_width;
var right_x = x + balloon_width + element_properties.balloon_margin.x + sidebar_width;
if (left_x > 0 && right_x > $(window).outerWidth()) {
x = left_x;
$balloon.addClass('leftPosition');
}
$balloon.css({
'left': x + 'px'
}).show();
$balloon.find('.delete-device').click(function(){
var $this = $(this);
var delete_modal = horizon.datatables.confirm($this);
delete_modal.find('.btn-primary').click(function () {
$this.prop('disabled', true);
d3.select('#id_' + $this.data('device-id')).classed('loading',true);
self.delete_device($this.data('type'),$this.data('device-id'));
horizon.modals.spinner.modal('hide');
});
});
$balloon.find('.delete-port').click(function(){
var $this = $(this);
var delete_modal = horizon.datatables.confirm($this);
delete_modal.find('.btn-primary').click(function () {
$this.prop('disabled', true);
self.delete_port($this.data('router-id'),$this.data('port-id'),$this.data('network-id'));
horizon.modals.spinner.modal('hide');
});
});
self.balloon_id = balloon_id;
},
delete_balloon:function() {
var self = this;
if(self.balloon_id) {
$('#' + self.balloon_id).remove();
self.balloon_id = null;
}
}
};
/**
* Licensed 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.
*/
/* global Hogan */
/* Namespace for core functionality related to Network Topology. */
function Network(data) {
for (var key in data) {
if ({}.hasOwnProperty.call(data, key)) {
this[key] = data[key];
}
}
this.iconType = 'text';
this.icon = '\uf0c2'; // Cloud
this.collapsed = false;
this.type = 'network';
this.instances = 0;
}
function ExternalNetwork(data) {
for (var key in data) {
if ({}.hasOwnProperty.call(data, key)) {
this[key] = data[key];
}
}
this.collapsed = false;
this.iconType = 'text';
this.icon = '\uf0ac'; // Globe
this.instances = 0;
}
function Router(data) {
for (var key in data) {
if ({}.hasOwnProperty.call(data, key)) {
this[key] = data[key];
}
}
this.iconType = 'path';
this.svg = 'router';
this.networks = [];
this.ports = [];
this.type = 'router';
}
function Server(data) {
for (var key in data) {
if ({}.hasOwnProperty.call(data, key)) {
this[key] = data[key];
}
}
this.iconType = 'text';
this.icon = '\uf108'; // Server
this.networks = [];
this.type = 'instance';
this.ip_addresses = [];
}
function listContains(obj, list) {
// Function to help checking if an object is present on a list
for (var i = 0; i < list.length; i++) {
if (angular.equals(list[i], obj)) {
return true;
}
}
return false;
}
horizon.network_topology = {
fa_globe_glyph: '\uf0ac',
fa_globe_glyph_width: 15,
svg:'#topology_canvas',
nodes: [],
links: [],
data: [],
zoom: d3.behavior.zoom(),
data_loaded: false,
svg_container:'#topologyCanvasContainer',
balloonTmpl : null,
balloon_deviceTmpl : null,
balloon_portTmpl : null,
balloon_netTmpl : null,
balloon_instanceTmpl : null,
network_index: {},
balloonID:null,
network_height : 0,
init:function() {
var self = this;
self.$loading_template = horizon.networktopologyloader.setup_loader($(self.svg_container));
if (angular.element('#networktopology').length === 0) {
return;
}
self.data = {};
self.data.networks = {};
self.data.routers = {};
self.data.servers = {};
self.data.ports = {};
// Setup balloon popups
self.balloonTmpl = Hogan.compile(angular.element('#balloon_container').html());
self.balloon_deviceTmpl = Hogan.compile(angular.element('#balloon_device').html());
self.balloon_portTmpl = Hogan.compile(angular.element('#balloon_port').html());
self.balloon_netTmpl = Hogan.compile(angular.element('#balloon_net').html());
self.balloon_instanceTmpl = Hogan.compile(angular.element('#balloon_instance').html());
angular.element(document)
.on('click', 'a.closeTopologyBalloon', function(e) {
e.preventDefault();
self.delete_balloon();
})
.on('click', '.topologyBalloon', function(e) {
e.stopPropagation();
})
.on('click', 'a.vnc_window', function(e) {
e.preventDefault();
var vncWindow = window.open(angular.element(this).attr('href'), vncWindow, 'width=760,height=560');
self.delete_balloon();
});
angular.element('#toggle_labels').change(function() {
horizon.cookies.put('show_labels', this.checked);
self.refresh_labels();
});
angular.element('#toggle_networks').change(function() {
horizon.cookies.put('are_networks_collapsed', this.checked);
self.refresh_networks();
self.refresh_labels();
});
// set up loader first thing
self.$loading_template.show();
self.create_vis();
self.force_direction(0.05,70,-700);
if(horizon.networktopologyloader.model !== null) {
self.retrieve_network_info(true);
}
d3.select(window).on('resize', function() {
var width = angular.element('#topologyCanvasContainer').width();
var height = angular.element('#topologyCanvasContainer').height();
self.force.size([width, height]).resume();
});
angular.element('#networktopology').on('change', function() {
self.retrieve_network_info(true);
if(angular.equals(self.data.networks,{}) && angular.equals(self.data.routers,{}) &&
angular.equals(self.data.servers,{})){
$('.loader-inline').remove();
angular.element('#topologyCanvasContainer').find('svg').remove();
$(self.svg_container).addClass('noinfo');
return;
}
});
// register for message notifications
horizon.networktopologymessager.addMessageHandler(
this.handleMessage, this
);
},
// Shows/Hides graph labels
refresh_labels: function() {
var show_labels = horizon.cookies.get('show_labels') == 'true';
angular.element('.nodeLabel').toggle(show_labels);
},
// Collapses/Uncollapses networks in the graph
refresh_networks: function() {
var self = this;
var are_collapsed = horizon.cookies.get('are_networks_collapsed') == 'true';
for (var n in self.nodes) {
if ({}.hasOwnProperty.call(self.nodes, n)) {
if (self.nodes[n].data instanceof Network || self.nodes[n].data instanceof ExternalNetwork) {
self.collapse_network(self.nodes[n], are_collapsed);
}
}
}
},
// Load config from cookie
load_config: function() {
var self = this;
var labels = horizon.cookies.get('show_labels') == 'true';
var networks = horizon.cookies.get('are_networks_collapsed') == 'true';
if(networks) {
angular.element('#toggle_networks_label').addClass('active');
angular.element('#toggle_networks').prop('checked', networks);
self.refresh_networks();
}
if(labels) {
angular.element('#toggle_labels_label').addClass('active');
angular.element('#toggle_labels').prop('checked', labels);
self.refresh_labels();
}
},
handleMessage:function(message) {
var self = this;
var deleteData = horizon.networktopologymessager.delete_data;
horizon.modals.spinner.modal('hide');
if (message.type == 'success') {
self.remove_node_on_delete(deleteData);
}
},
// Get the json data about the current deployment
retrieve_network_info: function(force_start) {
var self = this;
self.data_loaded = true;
self.load_topology(horizon.networktopologyloader.model);
if (force_start) {
var i = 0;
self.force.start();
while (i <= 100) {
self.force.tick();
i++;
}
}
},
getScreenCoords: function(x, y) {
var self = this;
if (self.translate) {
var xn = self.translate[0] + x * self.zoom.scale();
var yn = self.translate[1] + y * self.zoom.scale();
return { x: xn, y: yn };
} else {
return { x: x, y: y };
}
},
// Setup the main visualisation
create_vis: function() {
var self = this;
angular.element('#topologyCanvasContainer').find('svg').remove();
// Main svg
self.outer_group = d3.select('#topologyCanvasContainer').append('svg')
.attr('width', '100%')
.attr('height', angular.element(document).height() - 270 + "px")
.attr('pointer-events', 'all')
.append('g')
.call(self.zoom
.scaleExtent([0.1,1.5])
.on('zoom', function() {
self.delete_balloon();
self.vis.attr('transform', 'translate(' + d3.event.translate + ')scale(' +
self.zoom.scale() + ')');
self.translate = d3.event.translate;
})
)
.on('dblclick.zoom', null);
// Background for capturing mouse events
self.outer_group.append('rect')
.attr('width', '100%')
.attr('height', '100%')
.attr('fill', 'white')
.on('click', function() {
self.delete_balloon();
});
// svg wrapper for nodes to sit on
self.vis = self.outer_group.append('g');
},
// Calculate the hulls that surround networks
convex_hulls: function(nodes) {
var net, _i, _len, _ref, _h, i;
var hulls = {};
var networkids = {};
var k = 0;
var offset = 40;
while (k < nodes.length) {
var n = nodes[k];
if (n.data !== undefined) {
if (n.data instanceof Server) {
_ref = n.data.networks;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
net = _ref[_i];
if (net instanceof Network) {
_h = hulls[net.id] || (hulls[net.id] = []);
_h.push([n.x - offset, n.y - offset]);
_h.push([n.x - offset, n.y + offset]);
_h.push([n.x + offset, n.y - offset]);
_h.push([n.x + offset, n.y + offset]);
}
}
} else if (n.data instanceof Network) {
net = n.data;
networkids[net.id] = n;
_h = hulls[net.id] || (hulls[net.id] = []);
_h.push([n.x - offset, n.y - offset]);
_h.push([n.x - offset, n.y + offset]);
_h.push([n.x + offset, n.y - offset]);
_h.push([n.x + offset, n.y + offset]);
}
}
++k;
}
var hullset = [];
for (i in hulls) {
if ({}.hasOwnProperty.call(hulls, i)) {
hullset.push({group: i, network: networkids[i], path: d3.geom.hull(hulls[i])});
}
}
return hullset;
},
// Setup the force direction
force_direction: function(grav, dist, ch) {
var self = this;
angular.element('[data-toggle="tooltip"]').tooltip({container: 'body'});
self.curve = d3.svg.line()
.interpolate('cardinal-closed')
.tension(0.85);
self.fill = d3.scale.category10();
self.force = d3.layout.force()
.gravity(grav)
.linkDistance(function(d) {
if (d.source.data instanceof Server || d.target.data instanceof Server) {
if (d.source.data.networks) {
return (dist * d.source.data.networks.length) + (5 * d.target.data.instances) + 20;
} else if (d.target.data.networks) {
return (dist * d.target.data.networks.length) + (5 * d.source.data.instances) + 20;
}
} else if (d.source.data instanceof Router || d.target.data instanceof Router) {
if (d.source.data.networks) {
if (d.source.data.networks.length === 0) {
return dist + 20;
} else if (d.target.data.instances) {
return dist * d.source.data.networks.length + (10 * d.target.data.instances) + 20;
}
return dist * d.source.data.networks.length + 20;
} else if (d.target.data.networks) {
if (d.target.data.networks.length === 0) {
return dist + 20;
} else if (d.source.data.instances) {
return dist * d.target.data.networks.length + (10 * d.source.data.instances) + 20;
}
return dist * d.source.data.networks.length + 20;
}
} else {
return dist;
}
})
.charge(ch)
.size([angular.element('#topologyCanvasContainer').width(),
angular.element('#topologyCanvasContainer').height()])
.nodes(self.nodes)
.links(self.links)
.on('tick', function() {
self.vis.selectAll('g.node')
.attr('transform', function(d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
self.vis.selectAll('line.link')
.attr('x1', function(d) { return d.source.x; })
.attr('y1', function(d) { return d.source.y; })
.attr('x2', function(d) { return d.target.x; })
.attr('y2', function(d) { return d.target.y; });
self.vis.selectAll('path.hulls')
.data(self.convex_hulls(self.vis.selectAll('g.node').data()))
.attr('d', function(d) {
return self.curve(d.path);
})
.enter().insert('path', 'g')
.attr('class', 'hulls')
.style('fill', function(d) {
return self.fill(d.group);
})
.style('stroke', function(d) {
return self.fill(d.group);
})
.style('stroke-linejoin', 'round')
.style('stroke-width', 10)
.style('opacity', 0.2);
});
},
// Create a new node
new_node: function(data, x, y) {
var self = this;
data = {data: data};
if (x && y) {
data.x = x;
data.y = y;
}
self.nodes.push(data);
var node = self.vis.selectAll('g.node').data(self.nodes);
var nodeEnter = node.enter().append('g')
.attr('class', 'node')
.style('fill', 'white')
.call(self.force.drag);
nodeEnter.append('circle')
.attr('class', 'frame')
.attr('r', function(d) {
switch (Object.getPrototypeOf(d.data)) {
case ExternalNetwork.prototype:
return 35;
case Network.prototype:
return 30;
case Router.prototype:
return 25;
case Server.prototype:
return 20;
}
})
.style('fill', 'white')
.style('stroke', 'black')
.style('stroke-width', 3);
switch (data.data.iconType) {
case 'text':
nodeEnter.append('text')
.style('fill', 'black')
.style('font', '20px FontAwesome')
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'central')
.text(function(d) { return d.data.icon; })
.attr('transform', function(d) {
switch (Object.getPrototypeOf(d.data)) {
case ExternalNetwork.prototype:
return 'scale(2.5)';
case Network.prototype:
return 'scale(1.5)';
case Server.prototype:
return 'scale(1)';
}
});
break;
case 'path':
nodeEnter.append('path')
.attr('class', 'svgpath')
.style('fill', 'black')
.attr('d', function(d) { return self.svgs(d.data.svg); })
.attr('transform', function() {
return 'scale(1.2)translate(-16,-15)';
});
break;
}
nodeEnter.append('text')
.attr('class', 'nodeLabel')
.style('display',function() {
var labels = horizon.cookies.get('topology_labels');
if (labels) {
return 'inline';
} else {
return 'none';
}
})
.style('fill','black')
.text(function(d) {
return d.data.name;
})
.attr('transform', function(d) {
switch (Object.getPrototypeOf(d.data)) {
case ExternalNetwork.prototype:
return 'translate(40,3)';
case Network.prototype:
return 'translate(35,3)';
case Router.prototype:
return 'translate(30,3)';
case Server.prototype:
return 'translate(25,3)';
}
});
if (data.data instanceof Network || data.data instanceof ExternalNetwork) {
nodeEnter.append('svg:text')
.attr('class','vmCount')
.style('fill', 'black')
.style('font-size','20')
.text('')
.attr('transform', 'translate(26,38)');
}
nodeEnter.on('click', function(d) {
self.show_balloon(d.data, d, angular.element(this));
});
// Highlight the links for currently selected node
nodeEnter.on('mouseover', function(d) {
self.vis.selectAll('line.link').filter(function(z) {
if (z.source === d || z.target === d) {
return true;
} else {
return false;
}
}).style('stroke-width', '3px');
});
// Remove the highlight on the links
nodeEnter.on('mouseout', function() {
self.vis.selectAll('line.link').style('stroke-width','1px');
});
},
collapse_network: function(d, only_collapse) {
var self = this;
var server, vm;
var filterNode = function(obj) {
return function(d) {
return obj == d.data;
};
};
if (!d.data.collapsed) {
var vmCount = 0;
for (vm in self.data.servers) {
if (self.data.servers[vm] !== undefined) {
if (self.data.servers[vm].networks.length == 1) {
if (self.data.servers[vm].networks[0].id == d.data.id) {
vmCount += 1;
self.removeNode(self.data.servers[vm]);
}
}
}
}
d.data.collapsed = true;
if (vmCount > 0) {
self.vis.selectAll('.vmCount').filter(filterNode(d.data))[0][0].textContent = vmCount;
}
} else if (!only_collapse) {
for (server in self.data.servers) {
if ({}.hasOwnProperty.call(self.data.servers, server)) {
var _vm = self.data.servers[server];
if (_vm !== undefined) {
if (_vm.networks.length === 1) {
if (_vm.networks[0].id == d.data.id) {
self.new_node(_vm, d.x, d.y);
self.new_link(self.find_by_id(_vm.id), self.find_by_id(d.data.id));
self.force.start();
}
}
}
}
}
d.data.collapsed = false;
self.vis.selectAll('.vmCount').filter(filterNode(d.data))[0][0].textContent = '';
var i = 0;
while (i <= 100) {
self.force.tick();
i++;
}
}
},
new_link: function(source, target) {
var self = this;
self.links.push({source: source, target: target});
var line = self.vis.selectAll('line.link').data(self.links);
line.enter().insert('line', 'g.node')
.attr('class', 'link')
.attr('x1', function(d) { return d.source.x; })
.attr('y1', function(d) { return d.source.y; })
.attr('x2', function(d) { return d.target.x; })
.attr('y2', function(d) { return d.target.y; })
.style('stroke', 'black')
.style('stroke-width', 2);
},
find_by_id: function(id) {
var self = this;
var obj, _i, _len, _ref;
_ref = self.vis.selectAll('g.node').data();
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
obj = _ref[_i];
if (obj.data.id == id) {
return obj;
}
}
return undefined;
},
already_in_graph: function(data, node) {
// Check for gateway that may not have unique id
if (data == this.data.ports) {
for (var p in data) {
if (JSON.stringify(data[p]) == JSON.stringify(node)) {
return true;
}
}
return false;
}
// All other node types have UUIDs
for (var n in data) {
if (n == node.id) {
return true;
}
}
return false;
},
load_topology: function(data) {
var self = this;
var net, _i, _netlen, _netref, rou, _j, _roulen, _rouref, port, _l, _portlen, _portref,
ser, _k, _serlen, _serref, obj, vmCount;
var change = false;
var filterNode = function(obj) {
return function(d) {
return obj == d.data;
};
};
// Networks
_netref = data.networks;
for (_i = 0, _netlen = _netref.length; _i < _netlen; _i++) {
net = _netref[_i];
var network = null;
if (net['router:external'] === true) {
network = new ExternalNetwork(net);
} else {
network = new Network(net);
}
if (!self.already_in_graph(self.data.networks, network)) {
self.new_node(network);
change = true;
} else {
obj = self.find_by_id(network.id);
if (obj) {
network.collapsed = obj.data.collapsed;
network.instances = obj.data.instances;
obj.data = network;
}
}
self.data.networks[network.id] = network;
}
// Routers
_rouref = data.routers;
for (_j = 0, _roulen = _rouref.length; _j < _roulen; _j++) {
rou = _rouref[_j];
var router = new Router(rou);
if (!self.already_in_graph(self.data.routers, router)) {
self.new_node(router);
change = true;
} else {
obj = self.find_by_id(router.id);
if (obj) {
// Keep networks list
router.networks = obj.data.networks;
// Keep ports list
router.ports = obj.data.ports;
obj.data = router;
}
}
self.data.routers[router.id] = router;
}
// Servers
_serref = data.servers;
for (_k = 0, _serlen = _serref.length; _k < _serlen; _k++) {
ser = _serref[_k];
var server = new Server(ser);
if (!self.already_in_graph(self.data.servers, server)) {
self.new_node(server);
change = true;
} else {
obj = self.find_by_id(server.id);
if (obj) {
// Keep networks list
server.networks = obj.data.networks;
// Keep ip address list
server.ip_addresses = obj.data.ip_addresses;
obj.data = server;
} else if (self.data.servers[server.id] !== undefined) {
// This is used when servers are hidden because the network is
// collapsed
server.networks = self.data.servers[server.id].networks;
server.ip_addresses = self.data.servers[server.id].ip_addresses;
}
}
self.data.servers[server.id] = server;
}
// Ports
_portref = data.ports;
for (_l = 0, _portlen = _portref.length; _l < _portlen; _l++) {
port = _portref[_l];
if (!self.already_in_graph(self.data.ports, port)) {
var device = self.find_by_id(port.device_id);
var _network = self.find_by_id(port.network_id);
if (angular.isDefined(device) && angular.isDefined(_network)) {
if (port.device_owner == 'compute:nova' || port.device_owner == 'compute:None') {
_network.data.instances++;
device.data.networks.push(_network.data);
if (port.fixed_ips) {
for(var ip in port.fixed_ips) {
if (!listContains(port.fixed_ips[ip], device.data.ip_addresses)) {
device.data.ip_addresses.push(port.fixed_ips[ip]);
}
}
}
// Remove the recently added node if connected to a network which is
// currently collapsed
if (_network.data.collapsed) {
if (device.data.networks.length == 1) {
self.data.servers[device.data.id].networks = device.data.networks;
self.data.servers[device.data.id].ip_addresses = device.data.ip_addresses;
self.removeNode(self.data.servers[port.device_id]);
vmCount = Number(self.vis.selectAll('.vmCount').filter(filterNode(_network.data))[0][0].textContent);
self.vis.selectAll('.vmCount').filter(filterNode(_network.data))[0][0].textContent = vmCount + 1;
continue;
}
}
} else if (port.device_owner == 'network:router_interface') {
device.data.networks.push(_network.data);
device.data.ports.push(port);
} else if (device.data.ports) {
device.data.ports.push(port);
}
self.new_link(self.find_by_id(port.device_id), self.find_by_id(port.network_id));
change = true;
} else if (angular.isDefined(_network) && port.device_owner == 'compute:nova') {
// Need to add a previously hidden node to the graph because it is
// connected to more than 1 network
if (_network.data.collapsed) {
server = self.data.servers[port.device_id];
server.networks.push(_network.data);
if (port.fixed_ips) {
for(var ip in port.fixed_ips) {
server.ip_addresses.push(port.fixed_ips[ip]);
}
}
self.new_node(server);
// decrease collapsed vm count on network
vmCount = Number(self.vis.selectAll('.vmCount').filter(filterNode(server.networks[0]))[0][0].textContent);
if (vmCount == 1) {
self.vis.selectAll('.vmCount').filter(filterNode(server.networks[0]))[0][0].textContent = '';
} else {
self.vis.selectAll('.vmCount').filter(filterNode(server.networks[0]))[0][0].textContent = vmCount - 1;
}
// Add back in first network link
self.new_link(self.find_by_id(port.device_id), self.find_by_id(server.networks[0].id));
// Add new link
self.new_link(self.find_by_id(port.device_id), self.find_by_id(port.network_id));
change = true;
}
}
}
self.data.ports[port.id+port.device_id+port.network_id] = port;
}
if (change) {
self.force.start();
}
self.load_config();
self.$loading_template.hide();
},
removeNode: function(obj) {
var filterNetwork, filterNode, n, node, _i, _len, _ref;
_ref = this.nodes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
n = _ref[_i];
if (n.data === obj) {
node = n;
break;
}
}
if (node) {
this.nodes.splice(this.nodes.indexOf(node), 1);
filterNode = function(obj) {
return function(d) {
return obj === d.data;
};
};
filterNetwork = function(obj) {
return function(d) {
return obj === d.network.data;
};
};
if (obj instanceof Network) {
this.vis.selectAll('.hulls').filter(filterNetwork(obj)).remove();
}
this.vis.selectAll('g.node').filter(filterNode(obj)).remove();
return this.removeNodesLinks(obj);
}
},
removeNodesLinks: function(node) {
var l, linksToRemove, _i, _j, _len, _len1, _ref;
linksToRemove = [];
_ref = this.links;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
l = _ref[_i];
if (l.source.data === node) {
linksToRemove.push(l);
} else if (l.target.data === node) {
linksToRemove.push(l);
}
}
for (_j = 0, _len1 = linksToRemove.length; _j < _len1; _j++) {
l = linksToRemove[_j];
this.removeLink(l);
}
return this.force.resume();
},
removeLink: function(link) {
var i, index, l, _i, _len, _ref;
index = -1;
_ref = this.links;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
l = _ref[i];
if (l === link) {
index = i;
break;
}
}
if (index !== -1) {
this.links.splice(index, 1);
}
return this.vis.selectAll('line.link').data(this.links).exit().remove();
},
delete_device: function(device_type, deviceId) {
var message = {id:deviceId};
var target = device_type === 'instance' ? 'instance?id=' + deviceId : device_type;
horizon.networktopologymessager.post_message(deviceId, target, message, device_type, 'delete', data={});
},
remove_node_on_delete: function(deleteData) {
var self = this;
var deviceId = deleteData.device_id;
switch (deleteData.device_type) {
case 'router':
self.removeNode(self.data.routers[deviceId]);
break;
case 'instance':
self.removeNode(self.data.servers[deviceId]);
this.data.servers[deviceId] = undefined;
break;
case 'network':
self.removeNode(self.data.networks[deviceId]);
break;
case 'port':
self.removePortOrSubnet(deviceId, deleteData.device_data);
break;
}
self.delete_balloon();
},
removePortOrSubnet: function(portId, deviceData) {
var self = this;
var routerId = deviceData.router_id;
var networkId = deviceData.network_id;
if (routerId) {
for (var l in self.links) {
var data = null;
if(self.links[l].source.data.id == routerId && self.links[l].target.data.id == networkId) {
data = self.links[l].source.data;
} else if (self.links[l].target.data.id == routerId && self.links[l].source.data.id == networkId) {
data = self.links[l].target.data;
}
if (data) {
for (var p in data.ports) {
if ((data.ports[p].id == portId) && (data.ports[p].network_id == networkId)) {
self.removeLink(self.links[l]);
// Update Router to remove deleted port
var router = self.find_by_id(routerId);
router.data.ports.splice(router.data.ports.indexOf(data.ports[p]), 1);
self.force.start();
return;
}
}
}
}
} else {
var networkData = self.find_by_id(networkId).data;
var subnets = networkData.subnets;
for (var subnet in subnets) {
if (subnets[subnet].id === portId) {
if (subnets.length == 1) {
delete(networkData.subnets);
} else {
subnets.splice(subnet, 1);
}
self.force.start();
break;
}
}
}
},
delete_port: function(routerId, portId, networkId) {
var message = {id:portId};
var data = {network_id:networkId,router_id:routerId};
if (routerId) {
horizon.networktopologymessager.post_message(portId, 'router/' + routerId + '/', message, 'port', 'delete', data);
} else {
horizon.networktopologymessager.post_message(portId, 'network/' + networkId + '/?tab=network_tabs__subnets_tab', message, 'port', 'delete', data);
}
},
show_balloon: function(d,d2,element) {
var self = this;
var balloonTmpl = self.balloonTmpl;
var deviceTmpl = self.balloon_deviceTmpl;
var portTmpl = self.balloon_portTmpl;
var netTmpl = self.balloon_netTmpl;
var instanceTmpl = self.balloon_instanceTmpl;
var balloonID = 'bl_' + d.id;
var ports = [];
var subnets = [];
if (self.balloonID) {
if (self.balloonID == balloonID) {
self.delete_balloon();
return;
}
self.delete_balloon();
}
self.force.stop();
if (d.hasOwnProperty('ports')) {
angular.element.each(d.ports, function(i, port) {
var object = {};
object.id = port.id;
object.router_id = port.device_id;
object.url = port.url;
object.port_status = port.status;
object.port_status_class = (port.original_status === 'ACTIVE') ? 'active' : 'down';
var ipAddress = '';
try {
for (var ip in port.fixed_ips) {
ipAddress += port.fixed_ips[ip].ip_address + ' ';
}
}catch(e) {
ipAddress = gettext('None');
}
var deviceOwner = '';
try {
deviceOwner = port.device_owner.replace('network:','');
}catch(e) {
deviceOwner = gettext('None');
}
var networkId = '';
try {
networkId = port.network_id;
}catch(e) {
networkId = gettext('None');
}
object.ip_address = ipAddress;
object.device_owner = deviceOwner;
object.network_id = networkId;
object.is_interface = (
deviceOwner === 'router_interface' ||
deviceOwner === 'router_gateway' ||
deviceOwner === 'ha_router_replicated_interface'
);
ports.push(object);
});
} else if (d.hasOwnProperty('subnets')) {
angular.element.each(d.subnets, function(i, snet) {
var object = {};
object.id = snet.id;
object.cidr = snet.cidr;
object.url = snet.url;
subnets.push(object);
});
}
var htmlData = {
balloon_id:balloonID,
id:d.id,
url:d.url,
name:d.name,
type:d.type,
delete_label: gettext('Delete'),
status:d.status,
status_class: (d.original_status === 'ACTIVE') ? 'active' : 'down',
status_label: gettext('STATUS'),
id_label: gettext('ID'),
interfaces_label: gettext('Interfaces'),
subnets_label: gettext('Subnets'),
delete_interface_label: gettext('Delete Interface'),
delete_subnet_label: gettext('Delete Subnet'),
open_console_label: gettext('Open Console'),
view_details_label: gettext('View Details'),
ips_label: gettext('IP Addresses')
};
var html;
if (d instanceof Router) {
htmlData.delete_label = gettext('Delete Router');
htmlData.view_details_label = gettext('View Router Details');
htmlData.port = ports;
htmlData.add_interface_url = 'router/' + d.id + '/addinterface';
htmlData.add_interface_label = gettext('Add Interface');
html = balloonTmpl.render(htmlData,{
table1:deviceTmpl,
table2:portTmpl
});
} else if (d instanceof Server) {
htmlData.delete_label = gettext('Delete Instance');
htmlData.view_details_label = gettext('View Instance Details');
htmlData.console_id = d.id;
htmlData.ips = d.ip_addresses;
htmlData.console = d.console;
html = balloonTmpl.render(htmlData,{
table1:deviceTmpl,
table2:instanceTmpl
});
} else if (d instanceof Network || d instanceof ExternalNetwork) {
for (var s in subnets) {
subnets[s].network_id = d.id;
}
htmlData.subnet = subnets;
if (d instanceof Network) {
htmlData.delete_label = gettext('Delete Network');
}
htmlData.add_subnet_url = 'network/' + d.id + '/subnet/create';
htmlData.add_subnet_label = gettext('Create Subnet');
html = balloonTmpl.render(htmlData,{
table1:deviceTmpl,
table2:netTmpl
});
} else {
return;
}
angular.element(self.svg_container).append(html);
var devicePosition = self.getScreenCoords(d2.x, d2.y);
var x = devicePosition.x;
var y = devicePosition.y;
var xoffset = 100;
var yoffset = 95;
angular.element('#' + balloonID).css({
'left': x + xoffset + 'px',
'top': y + yoffset + 'px'
}).show();
var _balloon = angular.element('#' + balloonID);
if (element.x + _balloon.outerWidth() > angular.element(window).outerWidth()) {
_balloon
.css({
'left': 0 + 'px'
})
.css({
'left': (x - _balloon.outerWidth() + 'px')
})
.addClass('leftPosition');
}
_balloon.find('.delete-device').click(function() {
var _this = angular.element(this);
var delete_modal = horizon.datatables.confirm(_this);
delete_modal.find('.btn.btn-danger').click(function () {
_this.prop('disabled', true);
d3.select('#id_' + _this.data('device-id')).classed('loading',true);
self.delete_device(_this.data('type'),_this.data('device-id'));
});
});
_balloon.find('.delete-port').click(function() {
var _this = angular.element(this);
var delete_modal = horizon.datatables.confirm(_this);
delete_modal.find('.btn.btn-danger').click(function () {
_this.prop('disabled', true);
self.delete_port(_this.data('router-id'),_this.data('port-id'),_this.data('network-id'));
});
});
self.balloonID = balloonID;
},
delete_balloon:function() {
var self = this;
if (self.balloonID) {
angular.element('#' + self.balloonID).remove();
self.balloonID = null;
self.force.start();
}
},
svgs: function(name) {
switch (name) {
case 'router':
return 'm 26.628571,16.08 -8.548572,0 0,8.548571 2.08,-2.079998 6.308572,6.30857 4.38857,-4.388572 -6.308571,-6.30857 z m -21.2571429,-4.159999 8.5485709,0 0,-8.5485723 -2.08,2.08 L 5.5314281,-0.85714307 1.1428571,3.5314287 7.4514281,9.84 z m -3.108571,7.268571 0,8.548571 8.5485709,0 L 8.7314281,25.657144 15.039999,19.325715 10.674285,14.96 4.3428571,21.268573 z M 29.737142,8.8114288 l 0,-8.54857147 -8.548572,0 2.08,2.07999987 -6.308571,6.3085716 4.388572,4.3885722 6.308571,-6.3085723 z';
default:
return '';
}
}
};
/**
* Licensed 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.
*/
// Aggregate for common network topology functionality
horizon.networktopologycommon = {
init:function() {
horizon.networktopologyloader.init();
horizon.networktopologymessager.init();
}
};
/**
* Common data loader for network topology views
*/
horizon.networktopologyloader = {
// data for the network topology views
model: null,
// timeout length
reload_duration: 10000,
// timer controlling update intervals
update_timer: null,
init:function() {
var self = this;
if($('#networktopology').length === 0) {
return;
}
self.update();
},
/**
* makes the data reqeuest and populates the 'model'
*/
update:function() {
var self = this;
angular.element.getJSON(
angular.element('#networktopology').data('networktopology') + '?' + angular.element.now(),
function(data) {
self.model = data;
$('#networktopology').trigger('change');
self.update_timer = setTimeout(function(){
self.update();
}, self.reload_duration);
}
);
},
/**
* stops the data update sequences
*/
stop_update:function() {
var self = this;
clearTimeout(self.update_timer);
},
// Set up loader template
setup_loader: function($container) {
return horizon.loader.inline(gettext('Loading')).hide().prependTo($container);
}
};
/**
* common utility for network topology view to create iframes and pass post
* messages from those iframes
*/
horizon.networktopologymessager = {
previous_message : null,
// element to attach messages to
post_messages:'#topologyMessages',
// Array of functions to call when a message event is received
messaging_functions: [],
// data stored when a delete operation is finalizing
delete_data: {},
init:function() {
var self = this;
// listens for message events
angular.element(window).on('message', function(e) {
var message = angular.element.parseJSON(e.originalEvent.data);
if (self.previous_message !== message.message) {
horizon.toast.add(message.type, message.message);
self.previous_message = message.message;
self.delete_post_message(message.iframe_id);
self.messageNotify(message);
horizon.networktopologyloader.update();
setTimeout(function() {
self.previous_message = null;
self.delete_data = {};
},self.reload_duration);
}
});
},
/**
* add method to be called when a message is received
*
* @param {function} fn method to be called
*
* @param {Object} fnObj object the method is being called from this make
* sure the scope of 'this' is correct
*/
addMessageHandler:function(fn, fnObj) {
var self = this;
self.messaging_functions.push({obj:fnObj, func:fn});
},
/**
* calls the methods that subscribed to message notifications
*
* @param {Object} message iframe message content
*/
messageNotify:function(message) {
var self = this;
for (var i = 0; i < self.messaging_functions.length; i += 1) {
func = self.messaging_functions[i].func;
fnObj = self.messaging_functions[i].obj;
func.call(fnObj, message);
}
},
/**
* posts a message from the iframe
*
* @param {String} id target device id
* @param {String} url URL for action
* @param {Object} message object containing message value
* @param {String} action value of action, e.g., "delete"
* @param {Object} data of extra data that should be relayed with the message
* notification
*/
post_message: function(id,url,message,type,action,data) {
var self = this;
if(action == "delete") {
self.delete_data.device_id = id;
self.delete_data.device_type = type;
self.delete_data.device_data = data;
}
// stop the update refesh cycle while action takes place
horizon.networktopologyloader.stop_update();
var iframeID = 'ifr_' + id;
var iframe = $('<iframe width="500" height="300" />')
.attr('id',iframeID)
.attr('src',url)
.appendTo('#topologyMessages');
iframe.on('load',function() {
angular.element(this).get(0).contentWindow.postMessage(
JSON.stringify(message, null, 2), '*');
});
},
// delete the iframe
delete_post_message: function(id) {
angular.element('#' + id).remove();
}
};
{% load i18n %} {% load i18n %}
{% load staticfiles %} {% load staticfiles %}
{% if not perms.vm.access_console %} {% if not True %}
<div class="alert alert-warning"> <div class="alert alert-warning">
{% trans "You are not authorized to access the VNC console." %} {% trans "You are not authorized to access the VNC console." %}
</div> </div>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
</div> </div>
{% if perms.vm.access_console %} {% if True %}
<div class="alert alert-info" id="noVNC_status"></div> <div class="alert alert-info" id="noVNC_status"></div>
{% endif %} {% endif %}
...@@ -40,12 +40,13 @@ ...@@ -40,12 +40,13 @@
<hr /> <hr />
</div> </div>
{% if perms.vm.access_console %} {% if True %}
<canvas id="noVNC_canvas" width="640" height="20">Canvas not supported. <iframe src="{{ vnc_url }}" style="width: 100%; height: 664px;"></iframe>
</canvas> {#<canvas id="noVNC_canvas" width="640" height="20">Canvas not supported.#}
{#</canvas>#}
<script> {#<script>#}
var INCLUDE_URI = '{% static "no-vnc/include/" %}'; {#var INCLUDE_URI = '{% static "no-vnc/include/" %}';#}
var VNC_URL = "{{ vnc_url }}"; {#var VNC_URL = "{{ vnc_url }}";#}
</script> {#</script>#}
{% endif %} {% endif %}
...@@ -116,10 +116,10 @@ class VmDetailView(LoginRequiredMixin, GraphMixin, DetailView): ...@@ -116,10 +116,10 @@ class VmDetailView(LoginRequiredMixin, GraphMixin, DetailView):
ops = get_operations(instance, user, self.request) ops = get_operations(instance, user, self.request)
hide_tutorial = self.request.COOKIES.get( hide_tutorial = self.request.COOKIES.get(
"hide_tutorial_for_%s" % instance.pk) == "True" "hide_tutorial_for_%s" % instance.pk) == "True"
vnc_console = openstack_api.nova.server_vnc_console(self.request, instance.os_server_id)
context.update({ context.update({
'graphite_enabled': settings.GRAPHITE_URL is not None, 'graphite_enabled': settings.GRAPHITE_URL is not None,
'vnc_url': reverse_lazy("dashboard.views.detail-vnc", 'vnc_url': vnc_console.url,
kwargs={'pk': self.object.pk}),
'ops': ops, 'ops': ops,
'op': {i.op: i for i in ops}, 'op': {i.op: i for i in ops},
# 'connect_commands': user.profile.get_connect_commands(instance), # 'connect_commands': user.profile.get_connect_commands(instance),
......
File added
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment