BigW Consortium Gitlab
Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
gitlab-ce
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Forest Godfrey
gitlab-ce
Commits
2d00d6d4
Commit
2d00d6d4
authored
Mar 06, 2018
by
Phil Hughes
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'cluster-monitoring-changes-ce-backport' into 'master'
Cluster monitoring changes CE backport See merge request gitlab-org/gitlab-ce!17547
parents
d12f60a5
226d43b3
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
225 additions
and
108 deletions
+225
-108
applications.vue
app/assets/javascripts/clusters/components/applications.vue
+4
-1
dashboard.vue
app/assets/javascripts/monitoring/components/dashboard.vue
+69
-17
graph.vue
app/assets/javascripts/monitoring/components/graph.vue
+15
-2
legend.vue
...assets/javascripts/monitoring/components/graph/legend.vue
+43
-35
graph_group.vue
app/assets/javascripts/monitoring/components/graph_group.vue
+15
-1
monitoring_bundle.js
app/assets/javascripts/monitoring/monitoring_bundle.js
+19
-4
monitoring_service.js
...ets/javascripts/monitoring/services/monitoring_service.js
+3
-0
index.js
...ts/javascripts/pages/projects/environments/index/index.js
+0
-0
environments.scss
app/assets/stylesheets/pages/environments.scss
+2
-1
metrics.html.haml
app/views/projects/environments/metrics.html.haml
+3
-2
environments.rb
spec/javascripts/fixtures/environments.rb
+0
-30
dashboard_spec.js
spec/javascripts/monitoring/dashboard_spec.js
+52
-15
No files found.
app/assets/javascripts/clusters/components/applications.vue
View file @
2d00d6d4
...
...
@@ -117,7 +117,10 @@
</
script
>
<
template
>
<section
class=
"settings no-animate expanded"
>
<section
id=
"cluster-applications"
class=
"settings no-animate expanded"
>
<div
class=
"settings-header"
>
<h4>
{{
s__
(
'ClusterIntegration|Applications'
)
}}
...
...
app/assets/javascripts/monitoring/components/dashboard.vue
View file @
2d00d6d4
...
...
@@ -7,34 +7,82 @@
import
EmptyState
from
'./empty_state.vue'
;
import
MonitoringStore
from
'../stores/monitoring_store'
;
import
eventHub
from
'../event_hub'
;
import
{
convertPermissionToBoolean
}
from
'../../lib/utils/common_utils'
;
export
default
{
components
:
{
Graph
,
GraphGroup
,
EmptyState
,
},
data
()
{
const
metricsData
=
document
.
querySelector
(
'#prometheus-graphs'
).
dataset
;
const
store
=
new
MonitoringStore
();
props
:
{
hasMetrics
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
showLegend
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
showPanels
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
forceSmallGraph
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
documentationPath
:
{
type
:
String
,
required
:
true
,
},
settingsPath
:
{
type
:
String
,
required
:
true
,
},
clustersPath
:
{
type
:
String
,
required
:
true
,
},
tagsPath
:
{
type
:
String
,
required
:
true
,
},
projectPath
:
{
type
:
String
,
required
:
true
,
},
metricsEndpoint
:
{
type
:
String
,
required
:
true
,
},
deploymentEndpoint
:
{
type
:
String
,
required
:
false
,
default
:
null
,
},
emptyGettingStartedSvgPath
:
{
type
:
String
,
required
:
true
,
},
emptyLoadingSvgPath
:
{
type
:
String
,
required
:
true
,
},
emptyUnableToConnectSvgPath
:
{
type
:
String
,
required
:
true
,
},
},
data
()
{
return
{
store
,
store
:
new
MonitoringStore
()
,
state
:
'gettingStarted'
,
hasMetrics
:
convertPermissionToBoolean
(
metricsData
.
hasMetrics
),
documentationPath
:
metricsData
.
documentationPath
,
settingsPath
:
metricsData
.
settingsPath
,
clustersPath
:
metricsData
.
clustersPath
,
tagsPath
:
metricsData
.
tagsPath
,
projectPath
:
metricsData
.
projectPath
,
metricsEndpoint
:
metricsData
.
additionalMetrics
,
deploymentEndpoint
:
metricsData
.
deploymentEndpoint
,
emptyGettingStartedSvgPath
:
metricsData
.
emptyGettingStartedSvgPath
,
emptyLoadingSvgPath
:
metricsData
.
emptyLoadingSvgPath
,
emptyUnableToConnectSvgPath
:
metricsData
.
emptyUnableToConnectSvgPath
,
showEmptyState
:
true
,
updateAspectRatio
:
false
,
updatedAspectRatios
:
0
,
...
...
@@ -67,6 +115,7 @@
window
.
addEventListener
(
'resize'
,
this
.
resizeThrottled
,
false
);
}
},
methods
:
{
getGraphsData
()
{
this
.
state
=
'loading'
;
...
...
@@ -115,6 +164,7 @@
v-for=
"(groupData, index) in store.groups"
:key=
"index"
:name=
"groupData.group"
:show-panels=
"showPanels"
>
<graph
v-for=
"(graphData, index) in groupData.metrics"
...
...
@@ -125,6 +175,8 @@
:deployment-data=
"store.deploymentData"
:project-path=
"projectPath"
:tags-path=
"tagsPath"
:show-legend=
"showLegend"
:small-graph=
"forceSmallGraph"
/>
</graph-group>
</div>
...
...
app/assets/javascripts/monitoring/components/graph.vue
View file @
2d00d6d4
...
...
@@ -52,6 +52,16 @@
type
:
String
,
required
:
true
,
},
showLegend
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
smallGraph
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
data
()
{
...
...
@@ -130,7 +140,7 @@
const
breakpointSize
=
bp
.
getBreakpointSize
();
const
query
=
this
.
graphData
.
queries
[
0
];
this
.
margin
=
measurements
.
large
.
margin
;
if
(
breakpointSize
===
'xs'
||
breakpointSize
===
'sm'
)
{
if
(
this
.
smallGraph
||
breakpointSize
===
'xs'
||
breakpointSize
===
'sm'
)
{
this
.
graphHeight
=
300
;
this
.
margin
=
measurements
.
small
.
margin
;
this
.
measurements
=
measurements
.
small
;
...
...
@@ -182,7 +192,9 @@
this
.
graphHeightOffset
,
);
if
(
this
.
timeSeries
.
length
>
3
)
{
if
(
!
this
.
showLegend
)
{
this
.
baseGraphHeight
-=
50
;
}
else
if
(
this
.
timeSeries
.
length
>
3
)
{
this
.
baseGraphHeight
=
this
.
baseGraphHeight
+=
(
this
.
timeSeries
.
length
-
3
)
*
20
;
}
...
...
@@ -255,6 +267,7 @@
:time-series=
"timeSeries"
:unit-of-display=
"unitOfDisplay"
:current-data-index=
"currentDataIndex"
:show-legend-group=
"showLegend"
/>
<svg
class=
"graph-data"
...
...
app/assets/javascripts/monitoring/components/graph/legend.vue
View file @
2d00d6d4
...
...
@@ -39,6 +39,11 @@
type
:
Number
,
required
:
true
,
},
showLegendGroup
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
},
data
()
{
return
{
...
...
@@ -57,8 +62,9 @@
},
rectTransform
()
{
const
yCoordinate
=
((
this
.
graphHeight
-
this
.
margin
.
top
)
/
2
)
+
(
this
.
yLabelWidth
/
2
)
+
10
||
0
;
const
yCoordinate
=
(((
this
.
graphHeight
-
this
.
margin
.
top
)
+
this
.
measurements
.
axisLabelLineOffset
)
/
2
)
+
(
this
.
yLabelWidth
/
2
)
||
0
;
return
`translate(0,
${
yCoordinate
}
) rotate(-90)`
;
},
...
...
@@ -166,39 +172,41 @@
>
Time
</text>
<g
class=
"legend-group"
v-for=
"(series, index) in timeSeries"
:key=
"index"
:transform=
"translateLegendGroup(index)"
>
<line
:stroke=
"series.lineColor"
:stroke-width=
"measurements.legends.height"
:stroke-dasharray=
"strokeDashArray(series.lineStyle)"
:x1=
"measurements.legends.offsetX"
:x2=
"measurements.legends.offsetX + measurements.legends.width"
:y1=
"graphHeight - measurements.legends.offsetY"
:y2=
"graphHeight - measurements.legends.offsetY"
/>
<text
v-if=
"timeSeries.length > 1"
class=
"legend-metric-title"
ref=
"legendTitleSvg"
x=
"38"
:y=
"graphHeight - 30"
>
{{
createSeriesString
(
index
,
series
)
}}
</text>
<text
v-else
class=
"legend-metric-title"
ref=
"legendTitleSvg"
x=
"38"
:y=
"graphHeight - 30"
<template
v-if=
"showLegendGroup"
>
<g
class=
"legend-group"
v-for=
"(series, index) in timeSeries"
:key=
"index"
:transform=
"translateLegendGroup(index)"
>
{{
legendTitle
}}
{{
formatMetricUsage
(
series
)
}}
</text>
</g>
<line
:stroke=
"series.lineColor"
:stroke-width=
"measurements.legends.height"
:stroke-dasharray=
"strokeDashArray(series.lineStyle)"
:x1=
"measurements.legends.offsetX"
:x2=
"measurements.legends.offsetX + measurements.legends.width"
:y1=
"graphHeight - measurements.legends.offsetY"
:y2=
"graphHeight - measurements.legends.offsetY"
/>
<text
v-if=
"timeSeries.length > 1"
class=
"legend-metric-title"
ref=
"legendTitleSvg"
x=
"38"
:y=
"graphHeight - 30"
>
{{
createSeriesString
(
index
,
series
)
}}
</text>
<text
v-else
class=
"legend-metric-title"
ref=
"legendTitleSvg"
x=
"38"
:y=
"graphHeight - 30"
>
{{
legendTitle
}}
{{
formatMetricUsage
(
series
)
}}
</text>
</g>
</
template
>
</g>
</template>
app/assets/javascripts/monitoring/components/graph_group.vue
View file @
2d00d6d4
...
...
@@ -5,12 +5,20 @@
type
:
String
,
required
:
true
,
},
showPanels
:
{
type
:
Boolean
,
required
:
false
,
default
:
true
,
},
},
};
</
script
>
<
template
>
<div
class=
"panel panel-default prometheus-panel"
>
<div
v-if=
"showPanels"
class=
"panel panel-default prometheus-panel"
>
<div
class=
"panel-heading"
>
<h4>
{{
name
}}
</h4>
</div>
...
...
@@ -18,4 +26,10 @@
<slot></slot>
</div>
</div>
<div
v-else
class=
"prometheus-graph-group"
>
<slot></slot>
</div>
</
template
>
app/assets/javascripts/monitoring/monitoring_bundle.js
View file @
2d00d6d4
import
Vue
from
'vue'
;
import
{
convertPermissionToBoolean
}
from
'~/lib/utils/common_utils'
;
import
Dashboard
from
'./components/dashboard.vue'
;
export
default
()
=>
new
Vue
({
el
:
'#prometheus-graphs'
,
render
:
createElement
=>
createElement
(
Dashboard
),
});
export
default
()
=>
{
const
el
=
document
.
getElementById
(
'prometheus-graphs'
);
if
(
el
&&
el
.
dataset
)
{
// eslint-disable-next-line no-new
new
Vue
({
el
,
render
(
createElement
)
{
return
createElement
(
Dashboard
,
{
props
:
{
...
el
.
dataset
,
hasMetrics
:
convertPermissionToBoolean
(
el
.
dataset
.
hasMetrics
),
},
});
},
});
}
};
app/assets/javascripts/monitoring/services/monitoring_service.js
View file @
2d00d6d4
...
...
@@ -40,6 +40,9 @@ export default class MonitoringService {
}
getDeploymentData
()
{
if
(
!
this
.
deploymentEndpoint
)
{
return
Promise
.
resolve
([]);
}
return
backOffRequest
(()
=>
axios
.
get
(
this
.
deploymentEndpoint
))
.
then
(
resp
=>
resp
.
data
)
.
then
((
response
)
=>
{
...
...
app/assets/javascripts/pages/projects/environments/index.js
→
app/assets/javascripts/pages/projects/environments/index
/index
.js
View file @
2d00d6d4
File moved
app/assets/stylesheets/pages/environments.scss
View file @
2d00d6d4
...
...
@@ -369,7 +369,8 @@
}
>
text
{
font-size
:
12px
;
fill
:
$theme-gray-600
;
font-size
:
10px
;
}
}
...
...
app/views/projects/environments/metrics.html.haml
View file @
2d00d6d4
...
...
@@ -15,7 +15,8 @@
"empty-getting-started-svg-path"
:
image_path
(
'illustrations/monitoring/getting_started.svg'
),
"empty-loading-svg-path"
:
image_path
(
'illustrations/monitoring/loading.svg'
),
"empty-unable-to-connect-svg-path"
:
image_path
(
'illustrations/monitoring/unable_to_connect.svg'
),
"additional-metrics"
:
additional_metrics_project_environment_path
(
@project
,
@environment
,
format: :json
),
"metrics-endpoint"
:
additional_metrics_project_environment_path
(
@project
,
@environment
,
format: :json
),
"deployment-endpoint"
:
project_environment_deployments_path
(
@project
,
@environment
,
format: :json
),
"project-path"
:
project_path
(
@project
),
"tags-path"
:
project_tags_path
(
@project
),
"has-metrics"
:
"#{@environment.has_metrics?}"
,
deployment_endpoint:
project_environment_deployments_path
(
@project
,
@environment
,
format: :json
)
}
}
"has-metrics"
:
"#{@environment.has_metrics?}"
}
}
spec/javascripts/fixtures/environments.rb
deleted
100644 → 0
View file @
d12f60a5
require
'spec_helper'
describe
Projects
::
EnvironmentsController
,
'(JavaScript fixtures)'
,
type: :controller
do
include
JavaScriptFixturesHelpers
let
(
:admin
)
{
create
(
:admin
)
}
let
(
:namespace
)
{
create
(
:namespace
,
name:
'frontend-fixtures'
)}
let
(
:project
)
{
create
(
:project_empty_repo
,
namespace:
namespace
,
path:
'environments-project'
)
}
let
(
:environment
)
{
create
(
:environment
,
name:
'production'
,
project:
project
)
}
render_views
before
(
:all
)
do
clean_frontend_fixtures
(
'environments/metrics'
)
end
before
do
sign_in
(
admin
)
end
it
'environments/metrics/metrics.html.raw'
do
|
example
|
get
:metrics
,
namespace_id:
project
.
namespace
,
project_id:
project
,
id:
environment
.
id
expect
(
response
).
to
be_success
store_frontend_fixture
(
response
,
example
.
description
)
end
end
spec/javascripts/monitoring/dashboard_spec.js
View file @
2d00d6d4
...
...
@@ -5,24 +5,35 @@ import axios from '~/lib/utils/axios_utils';
import
{
metricsGroupsAPIResponse
,
mockApiEndpoint
}
from
'./mock_data'
;
describe
(
'Dashboard'
,
()
=>
{
const
fixtureName
=
'environments/metrics/metrics.html.raw'
;
let
DashboardComponent
;
let
component
;
preloadFixtures
(
fixtureName
);
const
propsData
=
{
hasMetrics
:
false
,
documentationPath
:
'/path/to/docs'
,
settingsPath
:
'/path/to/settings'
,
clustersPath
:
'/path/to/clusters'
,
tagsPath
:
'/path/to/tags'
,
projectPath
:
'/path/to/project'
,
metricsEndpoint
:
mockApiEndpoint
,
deploymentEndpoint
:
null
,
emptyGettingStartedSvgPath
:
'/path/to/getting-started.svg'
,
emptyLoadingSvgPath
:
'/path/to/loading.svg'
,
emptyUnableToConnectSvgPath
:
'/path/to/unable-to-connect.svg'
,
};
beforeEach
(()
=>
{
loadFixtures
(
fixtureName
);
setFixtures
(
'<div class="prometheus-graphs"></div>'
);
DashboardComponent
=
Vue
.
extend
(
Dashboard
);
});
describe
(
'no metrics are available yet'
,
()
=>
{
it
(
'shows a getting started empty state when no metrics are present'
,
()
=>
{
component
=
new
DashboardComponent
({
el
:
document
.
querySelector
(
'#prometheus-graphs'
),
const
component
=
new
DashboardComponent
({
el
:
document
.
querySelector
(
'.prometheus-graphs'
),
propsData
,
});
component
.
$mount
();
expect
(
component
.
$el
.
querySelector
(
'#prometheus-graphs'
)).
toBe
(
null
);
expect
(
component
.
$el
.
querySelector
(
'.prometheus-graphs'
)).
toBe
(
null
);
expect
(
component
.
state
).
toEqual
(
'gettingStarted'
);
});
});
...
...
@@ -30,11 +41,8 @@ describe('Dashboard', () => {
describe
(
'requests information to the server'
,
()
=>
{
let
mock
;
beforeEach
(()
=>
{
document
.
querySelector
(
'#prometheus-graphs'
).
setAttribute
(
'data-has-metrics'
,
'true'
);
mock
=
new
MockAdapter
(
axios
);
mock
.
onGet
(
mockApiEndpoint
).
reply
(
200
,
{
metricsGroupsAPIResponse
,
});
mock
.
onGet
(
mockApiEndpoint
).
reply
(
200
,
metricsGroupsAPIResponse
);
});
afterEach
(()
=>
{
...
...
@@ -42,14 +50,43 @@ describe('Dashboard', () => {
});
it
(
'shows up a loading state'
,
(
done
)
=>
{
component
=
new
DashboardComponent
({
el
:
document
.
querySelector
(
'#prometheus-graphs'
),
const
component
=
new
DashboardComponent
({
el
:
document
.
querySelector
(
'.prometheus-graphs'
),
propsData
:
{
...
propsData
,
hasMetrics
:
true
},
});
component
.
$mount
();
Vue
.
nextTick
(()
=>
{
expect
(
component
.
state
).
toEqual
(
'loading'
);
done
();
});
});
it
(
'hides the legend when showLegend is false'
,
(
done
)
=>
{
const
component
=
new
DashboardComponent
({
el
:
document
.
querySelector
(
'.prometheus-graphs'
),
propsData
:
{
...
propsData
,
hasMetrics
:
true
,
showLegend
:
false
},
});
setTimeout
(()
=>
{
expect
(
component
.
showEmptyState
).
toEqual
(
false
);
expect
(
component
.
$el
.
querySelector
(
'.legend-group'
)).
toEqual
(
null
);
expect
(
component
.
$el
.
querySelector
(
'.prometheus-graph-group'
)).
toBeTruthy
();
done
();
});
});
it
(
'hides the group panels when showPanels is false'
,
(
done
)
=>
{
const
component
=
new
DashboardComponent
({
el
:
document
.
querySelector
(
'.prometheus-graphs'
),
propsData
:
{
...
propsData
,
hasMetrics
:
true
,
showPanels
:
false
},
});
setTimeout
(()
=>
{
expect
(
component
.
showEmptyState
).
toEqual
(
false
);
expect
(
component
.
$el
.
querySelector
(
'.prometheus-panel'
)).
toEqual
(
null
);
expect
(
component
.
$el
.
querySelector
(
'.prometheus-graph-group'
)).
toBeTruthy
();
done
();
});
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment