mirror of
https://github.com/ceph/ceph
synced 2025-01-20 01:51:34 +00:00
mgr/dashboard: Display useful info if RGW is not configured
Signed-off-by: Volker Theile <vtheile@suse.com>
This commit is contained in:
parent
f49e192dd5
commit
83441af93c
@ -31,6 +31,23 @@ class RgwControllerTest(DashboardTestCase):
|
||||
self.assertIn('rgw_status', data)
|
||||
self.assertTrue(data['rgw_metadata'])
|
||||
|
||||
@authenticate
|
||||
def test_rgw_status(self):
|
||||
self._radosgw_admin_cmd([
|
||||
'user', 'create', '--uid=admin', '--display-name=admin',
|
||||
'--system', '--access-key=admin', '--secret=admin'
|
||||
])
|
||||
self._ceph_cmd(['dashboard', 'set-rgw-api-user-id', 'admin'])
|
||||
self._ceph_cmd(['dashboard', 'set-rgw-api-secret-key', 'admin'])
|
||||
self._ceph_cmd(['dashboard', 'set-rgw-api-access-key', 'admin'])
|
||||
|
||||
data = self._get('/api/rgw/status')
|
||||
self.assertStatus(200)
|
||||
self.assertIn('available', data)
|
||||
self.assertIn('message', data)
|
||||
self.assertTrue(data['available'])
|
||||
|
||||
|
||||
class RgwProxyExceptionsTest(DashboardTestCase):
|
||||
|
||||
@classmethod
|
||||
|
@ -14,7 +14,27 @@ from ..rest_client import RequestException
|
||||
@ApiController('rgw')
|
||||
@AuthRequired()
|
||||
class Rgw(RESTController):
|
||||
pass
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
def status(self):
|
||||
status = {'available': False, 'message': None}
|
||||
try:
|
||||
instance = RgwClient.admin_instance()
|
||||
# Check if the service is online.
|
||||
if not instance.is_service_online():
|
||||
status['message'] = 'Failed to connect to the Object Gateway\'s Admin Ops API.'
|
||||
raise RequestException(status['message'])
|
||||
# If the API user ID is configured via 'ceph dashboard set-rgw-api-user-id <user_id>'
|
||||
# (which is not mandatory), then ensure it is known by the RGW.
|
||||
if instance.userid and not instance.is_system_user():
|
||||
status['message'] = 'The user "{}" is unknown to the Object Gateway.'.format(
|
||||
instance.userid)
|
||||
raise RequestException(status['message'])
|
||||
status['available'] = True
|
||||
except RequestException:
|
||||
pass
|
||||
return status
|
||||
|
||||
|
||||
@ApiController('rgw/daemon')
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
PerformanceCounterComponent
|
||||
} from './ceph/performance-counter/performance-counter/performance-counter.component';
|
||||
import { PoolListComponent } from './ceph/pool/pool-list/pool-list.component';
|
||||
import { Rgw501Component } from './ceph/rgw/rgw-501/rgw-501.component';
|
||||
import { RgwBucketFormComponent } from './ceph/rgw/rgw-bucket-form/rgw-bucket-form.component';
|
||||
import { RgwBucketListComponent } from './ceph/rgw/rgw-bucket-list/rgw-bucket-list.component';
|
||||
import { RgwDaemonListComponent } from './ceph/rgw/rgw-daemon-list/rgw-daemon-list.component';
|
||||
@ -24,6 +25,7 @@ import { RgwUserListComponent } from './ceph/rgw/rgw-user-list/rgw-user-list.com
|
||||
import { LoginComponent } from './core/auth/login/login.component';
|
||||
import { NotFoundComponent } from './core/not-found/not-found.component';
|
||||
import { AuthGuardService } from './shared/services/auth-guard.service';
|
||||
import { ModuleStatusGuardService } from './shared/services/module-status-guard.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
@ -31,40 +33,53 @@ const routes: Routes = [
|
||||
{ path: 'hosts', component: HostsComponent, canActivate: [AuthGuardService] },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'hosts', component: HostsComponent, canActivate: [AuthGuardService] },
|
||||
{ path: 'rgw/501/:message', component: Rgw501Component, canActivate: [AuthGuardService] },
|
||||
{
|
||||
path: 'rgw/daemon',
|
||||
component: RgwDaemonListComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'rgw/user',
|
||||
component: RgwUserListComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'rgw/user/add',
|
||||
component: RgwUserFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'rgw/user/edit/:uid',
|
||||
component: RgwUserFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'rgw/bucket',
|
||||
component: RgwBucketListComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'rgw/bucket/add',
|
||||
component: RgwBucketFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'rgw/bucket/edit/:bucket',
|
||||
component: RgwBucketFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
path: 'rgw',
|
||||
canActivateChild: [ModuleStatusGuardService],
|
||||
data: {
|
||||
moduleStatusGuardConfig: {
|
||||
apiPath: 'rgw',
|
||||
redirectTo: 'rgw/501'
|
||||
}
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'daemon',
|
||||
component: RgwDaemonListComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'user',
|
||||
component: RgwUserListComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'user/add',
|
||||
component: RgwUserFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'user/edit/:uid',
|
||||
component: RgwUserFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'bucket',
|
||||
component: RgwBucketListComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'bucket/add',
|
||||
component: RgwBucketFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'bucket/edit/:bucket',
|
||||
component: RgwBucketFormComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
}
|
||||
]
|
||||
},
|
||||
{ path: 'block/iscsi', component: IscsiComponent, canActivate: [AuthGuardService] },
|
||||
{ path: 'block/rbd', component: RbdListComponent, canActivate: [AuthGuardService] },
|
||||
|
@ -0,0 +1,12 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li i18n
|
||||
class="breadcrumb-item">Object Gateway</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<cd-info-panel>
|
||||
{{ message }}
|
||||
<ng-container i18n>
|
||||
Please consult the <a href="http://docs.ceph.com/docs/mimic/mgr/dashboard/#enabling-the-object-gateway-management-frontend">documentation</a> on how to configure and enable the Object Gateway management functionality.
|
||||
</ng-container>
|
||||
</cd-info-panel>
|
@ -0,0 +1,6 @@
|
||||
.alert-row-icon {
|
||||
vertical-align: top;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.alert-row-text {
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { SharedModule } from '../../../shared/shared.module';
|
||||
import { Rgw501Component } from './rgw-501.component';
|
||||
|
||||
describe('Rgw501Component', () => {
|
||||
let component: Rgw501Component;
|
||||
let fixture: ComponentFixture<Rgw501Component>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ Rgw501Component ],
|
||||
imports: [
|
||||
RouterTestingModule,
|
||||
SharedModule
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(Rgw501Component);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@Component({
|
||||
selector: 'cd-rgw-501',
|
||||
templateUrl: './rgw-501.component.html',
|
||||
styleUrls: ['./rgw-501.component.scss']
|
||||
})
|
||||
export class Rgw501Component implements OnInit, OnDestroy {
|
||||
message = 'The Object Gateway service is not configured.';
|
||||
routeParamsSubscribe: any;
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.routeParamsSubscribe = this.route.params.subscribe((params: { message: string }) => {
|
||||
this.message = params.message;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.routeParamsSubscribe.unsubscribe();
|
||||
}
|
||||
}
|
@ -2,11 +2,18 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { BsDropdownModule, ModalModule, TabsModule, TooltipModule } from 'ngx-bootstrap';
|
||||
import {
|
||||
AlertModule,
|
||||
BsDropdownModule,
|
||||
ModalModule,
|
||||
TabsModule,
|
||||
TooltipModule
|
||||
} from 'ngx-bootstrap';
|
||||
|
||||
import { AppRoutingModule } from '../../app-routing.module';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { PerformanceCounterModule } from '../performance-counter/performance-counter.module';
|
||||
import { Rgw501Component } from './rgw-501/rgw-501.component';
|
||||
import { RgwBucketDetailsComponent } from './rgw-bucket-details/rgw-bucket-details.component';
|
||||
import { RgwBucketFormComponent } from './rgw-bucket-form/rgw-bucket-form.component';
|
||||
import { RgwBucketListComponent } from './rgw-bucket-list/rgw-bucket-list.component';
|
||||
@ -45,12 +52,14 @@ import {
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
PerformanceCounterModule,
|
||||
AlertModule.forRoot(),
|
||||
BsDropdownModule.forRoot(),
|
||||
TabsModule.forRoot(),
|
||||
TooltipModule.forRoot(),
|
||||
ModalModule.forRoot()
|
||||
],
|
||||
exports: [
|
||||
Rgw501Component,
|
||||
RgwDaemonListComponent,
|
||||
RgwDaemonDetailsComponent,
|
||||
RgwBucketFormComponent,
|
||||
@ -60,6 +69,7 @@ import {
|
||||
RgwUserDetailsComponent
|
||||
],
|
||||
declarations: [
|
||||
Rgw501Component,
|
||||
RgwDaemonListComponent,
|
||||
RgwDaemonDetailsComponent,
|
||||
RgwBucketFormComponent,
|
||||
|
Loading…
Reference in New Issue
Block a user