Skip to content

Commit c58a552

Browse files
committed
rquota: add possibility to set quota.
Modification: added `org.dcache.rquota.QuotaVfs#setQuota` added unit test Fixes: #133 Acked-by: Lea Morschel Target: master
1 parent 0597235 commit c58a552

File tree

3 files changed

+140
-19
lines changed

3 files changed

+140
-19
lines changed

rquota/src/main/java/org/dcache/rquota/QuotaSvc.java

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import static org.dcache.rquota.QuotaVfs.GROUP_QUOTA;
2323
import static org.dcache.rquota.QuotaVfs.USER_QUOTA;
24+
import org.dcache.nfs.ExportTable;
25+
import org.dcache.nfs.FsExport;
2426
import org.dcache.nfs.util.SubjectHolder;
2527
import org.dcache.nfs.util.UnixSubjects;
2628
import org.dcache.oncrpc4j.rpc.RpcCall;
@@ -33,17 +35,20 @@
3335
import org.dcache.rquota.xdr.setquota_args;
3436
import org.dcache.rquota.xdr.setquota_rslt;
3537
import org.slf4j.Logger;
38+
import org.slf4j.LoggerFactory;
3639

3740
import javax.security.auth.Subject;
3841

3942
public class QuotaSvc extends rquotaServerStub {
4043

41-
private final static Logger LOGGER = org.slf4j.LoggerFactory.getLogger(QuotaSvc.class);
44+
private final static Logger LOGGER = LoggerFactory.getLogger(QuotaSvc.class);
4245

43-
private final QuotaVfs _qfs;
46+
private final QuotaVfs qfs;
47+
private final ExportTable exportTable;
4448

45-
public QuotaSvc(QuotaVfs _qfs) {
46-
this._qfs = _qfs;
49+
public QuotaSvc(QuotaVfs qfs, ExportTable exportTable) {
50+
this.qfs = qfs;
51+
this.exportTable = exportTable;
4752
}
4853

4954
@Override
@@ -76,7 +81,7 @@ public getquota_rslt RQUOTAPROC_GETQUOTA_2(RpcCall call$, ext_getquota_args arg1
7681
}
7782

7883
r.status = qr_status.Q_OK;
79-
r.gqr_rquota = _qfs.getQuota(arg1.gqa_id, arg1.gqa_type);
84+
r.gqr_rquota = qfs.getQuota(arg1.gqa_id, arg1.gqa_type);
8085
return r;
8186
}
8287

@@ -90,18 +95,53 @@ public getquota_rslt RQUOTAPROC_GETACTIVEQUOTA_2(RpcCall call$, ext_getquota_arg
9095
}
9196

9297
r.status = qr_status.Q_OK;
93-
r.gqr_rquota = _qfs.getQuota(arg1.gqa_id, arg1.gqa_type);
98+
r.gqr_rquota = qfs.getQuota(arg1.gqa_id, arg1.gqa_type);
9499
return r;
95100
}
96101

97102
@Override
98103
public setquota_rslt RQUOTAPROC_SETQUOTA_2(RpcCall call$, ext_setquota_args arg1) {
99-
throw new UnsupportedOperationException("Not supported yet.");
104+
105+
setquota_rslt result = new setquota_rslt();
106+
String path = "/" + arg1.sqa_pathp; // leading slash is never sent by the client
107+
108+
109+
FsExport export = exportTable.getExport(path, call$.getTransport().getRemoteSocketAddress().getAddress());
110+
if (export == null) {
111+
result.status = qr_status.Q_EPERM;
112+
return result;
113+
}
114+
115+
if (!(UnixSubjects.isRootSubject(call$.getCredential().getSubject()) && export.isTrusted())) {
116+
result.status = qr_status.Q_EPERM;
117+
return result;
118+
}
119+
120+
result.sqr_rquota = qfs.setQuota(arg1.sqa_id, arg1.sqa_type, arg1.sqa_dqblk);
121+
result.status = qr_status.Q_OK;
122+
return result;
100123
}
101124

102125
@Override
103126
public setquota_rslt RQUOTAPROC_SETACTIVEQUOTA_2(RpcCall call$, ext_setquota_args arg1) {
104-
throw new UnsupportedOperationException("Not supported yet.");
127+
setquota_rslt result = new setquota_rslt();
128+
String path = "/" + arg1.sqa_pathp; // leading slash is never sent by the client
129+
130+
131+
FsExport export = exportTable.getExport(path, call$.getTransport().getRemoteSocketAddress().getAddress());
132+
if (export == null) {
133+
result.status = qr_status.Q_EPERM;
134+
return result;
135+
}
136+
137+
if (!(UnixSubjects.isRootSubject(call$.getCredential().getSubject()) && export.isTrusted())) {
138+
result.status = qr_status.Q_EPERM;
139+
return result;
140+
}
141+
142+
result.sqr_rquota = qfs.setQuota(arg1.sqa_id, arg1.sqa_type, arg1.sqa_dqblk);
143+
result.status = qr_status.Q_OK;
144+
return result;
105145
}
106146

107147
/**

rquota/src/main/java/org/dcache/rquota/QuotaVfs.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.dcache.rquota;
2121

2222
import org.dcache.rquota.xdr.rquota;
23+
import org.dcache.rquota.xdr.sq_dqblk;
2324

2425
/**
2526
* Interface for querying quotas.
@@ -41,7 +42,17 @@ public interface QuotaVfs {
4142
*
4243
* @param id numeric id of user or group to get quota for.
4344
* @param type type of quota to get, either {@link #USER_QUOTA} or {@link #GROUP_QUOTA}.
44-
* @return the quota for the given subject
45+
* @return the quota for the given id and type
4546
*/
4647
rquota getQuota(int id, int type);
48+
49+
/**
50+
* Set the quota for the given id.
51+
*
52+
* @param id numeric id of user or group to set quota for.
53+
* @param type type of quota to set, either {@link #USER_QUOTA} or {@link #GROUP_QUOTA}.
54+
* @param quota the quota to set
55+
* @return the new quota for the given id and type
56+
*/
57+
rquota setQuota(int id, int type, sq_dqblk quota);
4758
}

rquota/src/test/java/org/dcache/rquota/QuotaSvcTest.java

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,48 @@
33
import static org.dcache.rquota.QuotaVfs.GROUP_QUOTA;
44
import static org.dcache.rquota.QuotaVfs.USER_QUOTA;
55
import static org.junit.Assert.*;
6+
import static org.mockito.ArgumentMatchers.any;
7+
import static org.mockito.ArgumentMatchers.anyString;
68
import static org.mockito.Mockito.mock;
9+
import static org.mockito.Mockito.when;
10+
import org.dcache.nfs.ExportTable;
11+
import org.dcache.nfs.FsExport;
712
import org.dcache.nfs.util.UnixSubjects;
813
import org.dcache.oncrpc4j.rpc.RpcAuth;
914
import org.dcache.oncrpc4j.rpc.RpcCall;
15+
import org.dcache.oncrpc4j.rpc.RpcTransport;
1016
import org.dcache.rquota.xdr.ext_getquota_args;
17+
import org.dcache.rquota.xdr.ext_setquota_args;
1118
import org.dcache.rquota.xdr.getquota_rslt;
1219
import org.dcache.rquota.xdr.qr_status;
20+
import org.dcache.rquota.xdr.setquota_rslt;
1321
import org.junit.Before;
1422
import org.junit.Test;
15-
import org.mockito.Mockito;
23+
24+
import java.net.InetSocketAddress;
25+
import java.net.UnknownHostException;
1626

1727
public class QuotaSvcTest {
1828

1929
private QuotaVfs quotaVfs;
2030
private QuotaSvc quotaSvc;
2131
private RpcCall call;
2232
private RpcAuth auth;
33+
private ExportTable exportTable;
34+
private RpcTransport transport;
2335

2436
@Before
2537
public void setUp() {
2638
quotaVfs = mock(QuotaVfs.class);
27-
quotaSvc = new QuotaSvc(quotaVfs);
39+
exportTable = mock(ExportTable.class);
40+
quotaSvc = new QuotaSvc(quotaVfs, exportTable);
2841
call = mock(RpcCall.class);
2942
auth = mock(RpcAuth.class);
43+
when(call.getCredential()).thenReturn(auth);
44+
45+
transport = mock(RpcTransport.class);
46+
when(transport.getRemoteSocketAddress()).thenReturn(new InetSocketAddress(0));
47+
when(call.getTransport()).thenReturn(transport);
3048
}
3149

3250
@Test
@@ -35,8 +53,7 @@ public void testGetQuotaWrongUser() {
3553
args.gqa_id = 1;
3654
args.gqa_type = USER_QUOTA;
3755

38-
Mockito.when(call.getCredential()).thenReturn(auth);
39-
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(2, 2));
56+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(2, 2));
4057
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
4158
assertEquals(qr_status.Q_EPERM, result.status);
4259
}
@@ -47,8 +64,7 @@ public void testGetQuotaWrongGroup() {
4764
args.gqa_id = 1;
4865
args.gqa_type = GROUP_QUOTA;
4966

50-
Mockito.when(call.getCredential()).thenReturn(auth);
51-
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(2, 2));
67+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(2, 2));
5268
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
5369
assertEquals(qr_status.Q_EPERM, result.status);
5470
}
@@ -59,8 +75,7 @@ public void testGetUserQuota() {
5975
args.gqa_id = 1;
6076
args.gqa_type = USER_QUOTA;
6177

62-
Mockito.when(call.getCredential()).thenReturn(auth);
63-
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(1, 1));
78+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(1, 1));
6479
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
6580
assertEquals(qr_status.Q_OK, result.status);
6681
}
@@ -71,9 +86,64 @@ public void testGetGroupQuota() {
7186
args.gqa_id = 1;
7287
args.gqa_type = GROUP_QUOTA;
7388

74-
Mockito.when(call.getCredential()).thenReturn(auth);
75-
Mockito.when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(1, 1));
89+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(1, 1));
7690
getquota_rslt result = quotaSvc.RQUOTAPROC_GETQUOTA_2(call, args);
7791
assertEquals(qr_status.Q_OK, result.status);
7892
}
93+
94+
@Test
95+
public void testSetQuotaNoExport() {
96+
ext_setquota_args args = new ext_setquota_args();
97+
args.sqa_id = 1;
98+
args.sqa_type = GROUP_QUOTA;
99+
100+
when(exportTable.getExport(anyString(), any())).thenReturn(null);
101+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(0, 0));
102+
setquota_rslt result = quotaSvc.RQUOTAPROC_SETQUOTA_2(call, args);
103+
assertEquals(qr_status.Q_EPERM, result.status);
104+
}
105+
106+
@Test
107+
public void testSetQuotaNotRoot() {
108+
ext_setquota_args args = new ext_setquota_args();
109+
args.sqa_id = 1;
110+
args.sqa_type = GROUP_QUOTA;
111+
112+
when(exportTable.getExport(anyString(), any())).thenReturn(mock(FsExport.class));
113+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(2, 2));
114+
setquota_rslt result = quotaSvc.RQUOTAPROC_SETQUOTA_2(call, args);
115+
assertEquals(qr_status.Q_EPERM, result.status);
116+
}
117+
118+
@Test
119+
public void testSetQuotaRootSquashed() throws UnknownHostException {
120+
ext_setquota_args args = new ext_setquota_args();
121+
args.sqa_id = 1;
122+
args.sqa_type = GROUP_QUOTA;
123+
124+
when(exportTable.getExport(anyString(), any())).thenReturn(new FsExport.FsExportBuilder()
125+
.notTrusted()
126+
.forClient("*")
127+
.build("/"));
128+
129+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(0, 0));
130+
setquota_rslt result = quotaSvc.RQUOTAPROC_SETQUOTA_2(call, args);
131+
assertEquals(qr_status.Q_EPERM, result.status);
132+
}
133+
134+
@Test
135+
public void testSetQuotaAsRoot() throws UnknownHostException {
136+
ext_setquota_args args = new ext_setquota_args();
137+
args.sqa_id = 1;
138+
args.sqa_type = GROUP_QUOTA;
139+
140+
when(exportTable.getExport(anyString(), any())).thenReturn(new FsExport.FsExportBuilder()
141+
.trusted()
142+
.forClient("*")
143+
.build("/"));
144+
145+
when(auth.getSubject()).thenReturn(UnixSubjects.toSubject(0, 0));
146+
setquota_rslt result = quotaSvc.RQUOTAPROC_SETQUOTA_2(call, args);
147+
assertEquals(qr_status.Q_OK, result.status);
148+
}
79149
}

0 commit comments

Comments
 (0)