From 61d62a296064e0330cffec7ed4b7914371b4984b Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 7 Aug 2020 15:10:17 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../personal_access_tokens_controller.rb | 8 +- app/helpers/application_helper.rb | 4 + app/models/ci/job_artifact.rb | 2 +- app/policies/personal_access_token_policy.rb | 3 +- .../dashboard/pod_dashboard_service.rb | 2 +- .../personal_access_tokens/revoke_service.rb | 36 +++++++ .../219867-replace-deprecated-button.yml | 5 + .../feat-artifact-expire-never-keyword.yml | 5 + config/prometheus/pod_metrics.yml | 88 +++++++++++++----- .../geo/replication/configuration.md | 3 +- .../img/adding_a_secondary_node.png | Bin 23555 -> 0 bytes .../img/adding_a_secondary_node_v13_3.png | Bin 0 -> 51774 bytes doc/administration/pages/index.md | 59 ++++++++++++ doc/ci/yaml/README.md | 8 +- doc/user/project/clusters/add_eks_clusters.md | 4 +- .../ci/build/artifacts/expire_in_parser.rb | 45 +++++++++ lib/gitlab/ci/config/entry/artifacts.rb | 2 +- .../config/entry/legacy_validation_helpers.rb | 20 +++- lib/gitlab/config/entry/validators.rb | 4 +- lib/gitlab/experimentation.rb | 3 + locale/gitlab.pot | 6 ++ .../profiles/personal_access_tokens_spec.rb | 7 +- spec/helpers/application_helper_spec.rb | 13 +++ .../build/artifacts/expire_in_parser_spec.rb | 55 +++++++++++ spec/lib/gitlab/ci/yaml_processor_spec.rb | 15 +++ .../personal_access_token_policy_spec.rb | 13 ++- .../api/ci/runner/jobs_artifacts_spec.rb | 10 ++ .../ci/create_job_artifacts_service_spec.rb | 19 +++- .../revoke_service_spec.rb | 44 +++++++++ 29 files changed, 432 insertions(+), 51 deletions(-) create mode 100644 app/services/personal_access_tokens/revoke_service.rb create mode 100644 changelogs/unreleased/219867-replace-deprecated-button.yml create mode 100644 changelogs/unreleased/feat-artifact-expire-never-keyword.yml delete mode 100644 doc/administration/geo/replication/img/adding_a_secondary_node.png create mode 100644 doc/administration/geo/replication/img/adding_a_secondary_node_v13_3.png create mode 100644 lib/gitlab/ci/build/artifacts/expire_in_parser.rb create mode 100644 spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb create mode 100644 spec/services/personal_access_tokens/revoke_service_spec.rb diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb index 30f25e8fdaa..21adc032940 100644 --- a/app/controllers/profiles/personal_access_tokens_controller.rb +++ b/app/controllers/profiles/personal_access_tokens_controller.rb @@ -20,12 +20,8 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController def revoke @personal_access_token = finder.find(params[:id]) - - if @personal_access_token.revoke! - flash[:notice] = _("Revoked personal access token %{personal_access_token_name}!") % { personal_access_token_name: @personal_access_token.name } - else - flash[:alert] = _("Could not revoke personal access token %{personal_access_token_name}.") % { personal_access_token_name: @personal_access_token.name } - end + service = PersonalAccessTokens::RevokeService.new(current_user, token: @personal_access_token).execute + service.success? ? flash[:notice] = service.message : flash[:alert] = service.message redirect_to profile_personal_access_tokens_path end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7cf68b26eab..3b061ce2e67 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -194,6 +194,10 @@ module ApplicationHelper 'https://' + promo_host end + def contact_sales_url + promo_url + '/sales' + end + def support_url Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || promo_url + '/getting-help/' end diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index 47ac19635ab..6df1538ce8c 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -284,7 +284,7 @@ module Ci def expire_in=(value) self.expire_at = if value - ChronicDuration.parse(value)&.seconds&.from_now + ::Gitlab::Ci::Build::Artifacts::ExpireInParser.new(value).seconds_from_now end end diff --git a/app/policies/personal_access_token_policy.rb b/app/policies/personal_access_token_policy.rb index c9b4c2d44d5..aa87550fd6b 100644 --- a/app/policies/personal_access_token_policy.rb +++ b/app/policies/personal_access_token_policy.rb @@ -3,7 +3,8 @@ class PersonalAccessTokenPolicy < BasePolicy condition(:is_owner) { user && subject.user_id == user.id } - rule { is_owner | admin }.policy do + rule { is_owner | admin & ~blocked }.policy do enable :read_token + enable :revoke_token end end diff --git a/app/services/metrics/dashboard/pod_dashboard_service.rb b/app/services/metrics/dashboard/pod_dashboard_service.rb index a4b3393409b..310f78c6a4b 100644 --- a/app/services/metrics/dashboard/pod_dashboard_service.rb +++ b/app/services/metrics/dashboard/pod_dashboard_service.rb @@ -7,7 +7,7 @@ module Metrics DASHBOARD_NAME = N_('K8s pod health') # SHA256 hash of dashboard content - DASHBOARD_VERSION = '0515db7a99078a2423b037f99251ba16bd163603c0a30229ae8aa7386e96421c' + DASHBOARD_VERSION = '3a91b32f91b2dd3d90275333c0ea3630b3f3f37c4296ede5b5eef59bf523d66b' SEQUENCE = [ STAGES::MetricEndpointInserter, diff --git a/app/services/personal_access_tokens/revoke_service.rb b/app/services/personal_access_tokens/revoke_service.rb new file mode 100644 index 00000000000..16ba42bd317 --- /dev/null +++ b/app/services/personal_access_tokens/revoke_service.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module PersonalAccessTokens + class RevokeService + attr_reader :token, :current_user + + def initialize(current_user = nil, params = { token: nil }) + @current_user = current_user + @token = params[:token] + end + + def execute + return ServiceResponse.error(message: 'Not permitted to revoke') unless revocation_permitted? + + if token.revoke! + ServiceResponse.success(message: success_message) + else + ServiceResponse.error(message: error_message) + end + end + + private + + def error_message + _("Could not revoke personal access token %{personal_access_token_name}.") % { personal_access_token_name: token.name } + end + + def success_message + _("Revoked personal access token %{personal_access_token_name}!") % { personal_access_token_name: token.name } + end + + def revocation_permitted? + Ability.allowed?(current_user, :revoke_token, token) + end + end +end diff --git a/changelogs/unreleased/219867-replace-deprecated-button.yml b/changelogs/unreleased/219867-replace-deprecated-button.yml new file mode 100644 index 00000000000..b454cc85104 --- /dev/null +++ b/changelogs/unreleased/219867-replace-deprecated-button.yml @@ -0,0 +1,5 @@ +--- +title: Replace deprecated button on vulnerability details page +merge_request: 38679 +author: +type: other diff --git a/changelogs/unreleased/feat-artifact-expire-never-keyword.yml b/changelogs/unreleased/feat-artifact-expire-never-keyword.yml new file mode 100644 index 00000000000..62d47e33187 --- /dev/null +++ b/changelogs/unreleased/feat-artifact-expire-never-keyword.yml @@ -0,0 +1,5 @@ +--- +title: Add support for never keyword in expire_in job artifacts +merge_request: 38578 +author: Fabio Huser +type: added diff --git a/config/prometheus/pod_metrics.yml b/config/prometheus/pod_metrics.yml index d5c418ba98e..b9395124405 100644 --- a/config/prometheus/pod_metrics.yml +++ b/config/prometheus/pod_metrics.yml @@ -15,55 +15,101 @@ panel_groups: panels: - title: "CPU usage" type: "line-chart" - y_label: "Cores per pod" + y_label: "Cores per container" metrics: - id: pod_cpu_usage_seconds_total - query_range: 'rate(container_cpu_usage_seconds_total{pod="{{pod}}",container="POD"}[5m])' + query_range: >- + sum( + rate(container_cpu_usage_seconds_total{pod="{{pod}}",container!="POD"}[5m]) + ) + by (container) unit: "cores" - label: pod + label: container + + - title: "CPU throttling" + type: "line-chart" + y_label: "Cores per container" + metrics: + - id: pod_cpu_cfs_throttle + query_range: >- + sum( + rate(container_cpu_cfs_throttled_seconds_total{pod="{{pod}}"}[5m]) + ) + by (container) + unit: "cores" + label: container + - group: Memory metrics panels: - title: "Memory usage working set" type: "line-chart" - y_label: "Working set memory (MiB)" + y_label: "Working set memory" metrics: - id: pod_memory_working_set - query_range: 'container_memory_working_set_bytes{pod="{{pod}}",container="POD"}/1024/1024' - unit: "MiB" - label: pod + query_range: >- + sum( + container_memory_working_set_bytes{pod="{{pod}}",container!="POD"} + ) by (container) + unit: "bytes" + label: container + - group: Network metrics panels: - title: "Network Receive (In)" type: "line-chart" - y_label: "Received (KiB/sec)" + y_label: "Received (bytes/sec)" metrics: - id: pod_network_receive - query_range: 'rate(container_network_receive_bytes_total{pod="{{pod}}",container="POD"}[5m])/1024' - unit: "KiB / sec" + query_range: >- + sum( + rate( + container_network_receive_bytes_total{pod="{{pod}}"}[5m] + ) + ) by (pod) + unit: "bytes" label: pod + - title: "Network Transmit (Out)" type: "line-chart" - y_label: "Transmitted (KiB/sec)" + y_label: "Transmitted (bytes/sec)" metrics: - id: pod_network_transmit - query_range: 'rate(container_network_transmit_bytes_total{pod="{{pod}}",container="POD"}[5m])/1024' - unit: "KiB / sec" + query_range: >- + sum( + rate( + container_network_transmit_bytes_total{pod="{{pod}}"}[5m] + ) + ) by (pod) + unit: bytes label: pod + - group: Disk metrics panels: - title: "Disk Reads" type: "line-chart" - y_label: "Disk reads (KiB/sec)" + y_label: "Disk reads (bytes/sec)" metrics: - id: pod_disk_reads - query_range: 'rate(container_fs_reads_bytes_total{container="POD",pod="{{pod}}"}[5m])/1024' - unit: "KiB / sec" - label: pod + query_range: >- + sum( + rate( + container_fs_reads_bytes_total{pod="{{pod}}", container!="POD"}[5m] + ) + ) by (container,device) + + unit: "bytes / sec" + label: "{{container}} {{device}}" + - title: "Disk Writes" type: "line-chart" - y_label: "Disk writes (KiB/sec)" + y_label: "Disk writes (bytes/sec)" metrics: - id: pod_disk_writes - query_range: 'rate(container_fs_writes_bytes_total{container="POD",pod="{{pod}}"}[5m])/1024' - unit: "KiB / sec" - label: pod + query_range: >- + sum( + rate( + container_fs_writes_bytes_total{pod="{{pod}}", container!="POD"}[5m] + ) + ) by (container,device) + unit: "bytes / sec" + label: "{{container}} {{device}}" diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md index 25c8e7c408a..74fa8e3b8f2 100644 --- a/doc/administration/geo/replication/configuration.md +++ b/doc/administration/geo/replication/configuration.md @@ -194,14 +194,13 @@ keys must be manually replicated to the **secondary** node. 1. Visit the **primary** node's **Admin Area > Geo** (`/admin/geo/nodes`) in your browser. 1. Click the **New node** button. - ![Add secondary node](img/adding_a_secondary_node.png) + ![Add secondary node](img/adding_a_secondary_node_v13_3.png) 1. Fill in **Name** with the `gitlab_rails['geo_node_name']` in `/etc/gitlab/gitlab.rb`. These values must always match *exactly*, character for character. 1. Fill in **URL** with the `external_url` in `/etc/gitlab/gitlab.rb`. These values must always match, but it doesn't matter if one ends with a `/` and the other doesn't. -1. **Do NOT** check the **This is a primary node** checkbox. 1. Optionally, choose which groups or storage shards should be replicated by the **secondary** node. Leave blank to replicate all. Read more in [selective synchronization](#selective-synchronization). diff --git a/doc/administration/geo/replication/img/adding_a_secondary_node.png b/doc/administration/geo/replication/img/adding_a_secondary_node.png deleted file mode 100644 index e33b690da1865be30cc895e12d86269c2710375d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23555 zcmc$`byQnX7cUrETA*kPh2jMY6mOvv2=3ZYihGL%4-(vqd+{P6xJx0pwrH^s+@W~z z;trF3--9{_L2SDcJAHhCj28vp706P6951}sHh^Hk1pppU z;XcIFyo&f0kNLm`OMZ|90IFi~Z@xUj{Kj(rBrgT1K+diu=F%-!AH?(XjD>gx6N_3`oX*4CDUghYLP{m95jRaI3=O3J~( zK~GOlXJ_a5_;^7kR(u;Jn1 z-rnBX+1ZMUil(Nfm6et4?d`q2z1rGZI2``__iqFO;o#sG9x3Sy1F_aAD@ANfsY?Q_Vx9JhK9PkyB8N1pPrs}b#*}?knZko z6bj|(=?R5GEiElaM@Q}K?83srA|oS}l$303Z5tXI%*@P8O-<+K=3HD{tgWqGU0wbB z{J>yvOiawTZ{Gp~1HHYyot&Hk0s`{$^S^%m8Wj~45fS0x;Sn4h?Ca|r6cpqdkb?yP zyaXu9NNTvx?k?;(KcAq*`RlxC;u30!qV`Zww5C+dNS1i|h=KN4?%~9r>DdTiph-bU zO-I+~{0Ykbz|XIB%*#w&Zomu9XImQ^Puc+TZennXnWaooH{x7Ko3rci3<*Z1{-@#( z_rC@JE_9y)u>d5P_y2~{Aj~3`fzhSIB`iP|j1D8q`AN6Mpm=mUTQ1uWL;AbsN|&b>_)jScu?ABx-+%_ar-d(i?Bfl{mhz&Q|F z0SyKL0Q-*UK_X&e7!S;Av$0(zku}%Z*?GPHEUtw!h2GAt-;7gym}z&vnBt6Pq1C>u zDmOGnq{ij;f>m6k$_6TpHW1(h0POH!GZoR<&L#(@-L;XzW0y)sXFckT4i;9j=R5eiNrfZY=pE&XoKcUd@rUCb3DeBoDulu&tT0u^}DuGn;~DY0G6`o7P@=y zwXs^dTneDv#0|2OD zgtpC;u9}eoAzdYIe}0Rr=2H%gkksYNFCWe(C*n?-G>U6g5(OazFE1y+vT?3y_ipT! zOHH4!hvZG?yw<4-jw9DqH$sW=0TLWiVE4Dot*LjYOS30I2OFB30Xkyo+5*R`CO4Xw zWg^^9nriQoki1aj9V-t{KIgUK>rDmqlD$0e$xI(fleT*A2gfoaT3{&Qe+RpOh-7S^ z1tSMe@iV%e{~8(H@Yh8L{jGGeJ}T$+%OnoWK91H9rytle*W)S>7$_d>WKhYEX;-m> zjAuJf|6`5`8e_zD{Dl^naVqF00cArzz?iA7(XyIUt^ZijX(YV(B$SS3V?5U-;S18`QyGOK+n7Nl6h+P}#k*ZTTDs zM?St4Jvfo|y)niGBX(`C*3Hr?GYA8-5wq591Td?R6Qv0zyYO+m%ESX#mh=IXkhcy1 zp!W>eY*l+<{Tvu;r{Kr428+q7=jf&CD z!D-m?nQhh7r_;kBlikY$TFkt4LCBLHi|4?xugB@sO@4In0v_;8ZA;rTdS3zM2?!~0 z%-iz4b`9-^rB;IFQ}>&uU3Y|DtJr^-B?YpkTuE(qw}tk` zxrqAU@p<_V`{P%|4Cm39?DiIG?@k7k3vL~yLPZl* zdyQK7;FYNX3^gf4p|%tfv;^x))my(TMSf3{Wlf~<5!ElB{PDFCRj2d|Z_Ae_UGGJv z#Mn>s_ya9tAG(#adjC*`KH#E;HQVGIJDJ~TLSfHgfYVsyyz~fO*$#Se-8BN_e&-k?nY)Nj_c93*C&Ik!oxgt9O65cm>rCp;Kb#%KyL(t z*?YRix@C8M(D@mpq5jK-v=`nxW2i6L!In8oHn@7DFbY`Py@8m_tb=M|A z%KQ7XxNSapaywR3;z;9*6lxh(iPl`c_vZGiPEgRRr;R_p&ELe!ZHn7*iNC>I2t)@5|;Vo%a5a>vsXZ3&V68N*G6uY0K8{zjDbd( z?sdq@a>KN#cmPWjGMo~=g{_l-rfHzN_tA<*o?*7i#4EXe$uW?^5f6^M=TxDmItJd9 z9R=SD4=X*Oh0mX$R7O1Rx+8nnhY7gIWLYH^a`|p(ATd)$yv2fzZl8N=M-OAIpmbs9 z$O4FDuzr3w1w$9>Ad&oGJk#|aE6QM`(c9%B;3W`in;sUdlVHfoK9aiCZg~3w%nV!w z3rl+wZ#VbnkipbBLe5C9@!o-$@rRuKrV)__S)) zm)zrzo({S1f!7Ot*e3T5hhg+q7@o1o*q4+z;B^Zp*Y zzeik4t}mQeLs?Q*zjKFy{ApD=5+1lWECTaH$OE)L#K@jMHTe#5(Dy*Fjg|rdJ^T(rc70x6);&uO)$<7=KbV7c9Vg?uaezf-`?{N;nG(Osl`y@+YtF&$EGw`UXnapx&ru4x~XXSJSdf&nVPEKM@c^iu;cLppzWfL1Zmw(j#N z7MBsM@;j8Ul2v%K9;YUvF$E65%rXgw5<*Y|epyK%06`k`=T!!j@W5b_btfQMZ7`D$ zGq2DVmC^ehH=LT7l;L*?M3%RTo4t=oV1VtR*N?s4>W1gZuk-gYG zl ziThOo^1}r8D*#4pHI*IhYv$mK_8WS@FV0J5DeJiuN!f*S79Xglp>>IT!&jU{>{S;iyKu`2lVlR~jRuSs52f;Er;` z1PHpIKDk5%TpFXArN?lEg<%#8C=lp{Z&sY>_l>vZeNN$Gki3O{ZGBlgA2jX#E&d)c zhS`6N17N}cn7Ns3OZdmVC+MhWnmMzaVcM~yka-3 zyr(S+tD=tUviJPVw?mmQ z0~wPIUGH3J(oK!P$v$>a2kJgIL3vpVpKrdsdU5}@e=fqTg2gb^>o2{TcJ_bR)c=xB zXj5sbG*j=kIZj0z|fvt05R&q6gVIvf4*{c zwm>k@rb2ZXO0G;`pze|!4h)Ty&PJGjUo!B1Rhj6w0vY{!a!B!x*6$a$0dAK$xEbZm zU^yjK_~x-*=E_S2B>^gz{y&|G?dkdR*}JRTwP<4Y!!UFatJ#A zVR8s^mfz9bJ~k$2CE@R|u@6?$AbU@TEh&ZSGp^#w0(Y!=1TjgEA^zVvd$cF zUy;(uP>}Lx16xVqt^TLKqANAdmPsGMz^4ymnIzFPYUd&Du?yZg^t2V<>WNEi&l{Q; zw!NXU;sVbez(}_j^Il-TPSeum=tgM&rdw&m4``UK_e_y`7?QPs2dlhFq#vj1;o2h% zS0jd6AlT1CzrXm>SQ_%U;jLSapN{DCTZv;%zpu_KmL$N~9p!Q6+>5MRXdj;r`fVxv z#kOOhEn|PzgStM>CJkL^D^Wej2txPil2-uwzNpYDYtGOd)~2HVMNSp!C$XWQSxgOC zi`)$Jl{pT4DX}@(S#jAt3VOaCJ|)0WS#5OS<$FLlu=F9HyNXqes#;k!aw~E7d1Qr% z+oH|L&TasyB>Gh;rBG{kO?kd*Q;7FaMZE_3 zamhJ$c0yU|N*B-W@luNy($=-8;*Q99aQzt;Z1--aXJlW(V8u8*JMwAG7u?xkl;TO= zz6UMlQkyR%RpEyWV_cD7yaLH7^E0(yx`QGW6z2{JlxwuMXEUrz!`sgB8Y_?7>I&_? zKBq-PQ<$@l^+72vvg#azf1qTkq!S3p3^U+O8 zdbe7{cn)=9UpH_h{gLG%3$?EY&!WF8t{|BUVj~ndYYt54R~ESCQe{Kb;?>UEZIV!w zsVvVBf4p9>CF5kP4_X;BUj_QK)N(E|3tTDEG^!QIsY4vES38qoG6}m(eJv*$59T=} z(TPkyxSaa#RAmkX<+WNy38l-a8u|!g0u)En~8zvhh58BwfHP%Oi$q| zZ9}9KiQtx3>`C>!U(YkT_|NVl|&(Ld#K$OoR)$~_KKG9z2nx%%gLyMMsjNRHnRMNp(V6ZVaNMGx}XUJlv=D>G(SUojC|w>vH3m*&Q~O*_5q|n6c&rz)ZG( zzu_8bJs4X!aDEl?vZAOj2h{)+$8E7ckP{BcGJFiHn-AlY9{)}c^fI>wiJjcaRL=Y9 zs3tnFCf5)i>ZU$GZ51UJ8A)xjS=l{&!q+)e652Rpx8d+y4)s1&w$jpTk0iY8rwkEH zF^&g3@2)Ei7CJTxueZu+1?lcqGrQ58R#w#FL}&VtDvui#)51>=(u0p@p(N%1B7^>u z>y~N08sGj#63qmTkVCboPrR=*uPI~0_MKC!ZI?w~HSao&G#~m~vH)QBiN#+e6ZAqU zx=PKdNDxi&9?K;=Iji;xH@gH9n}n%U&xZAoZ@Uv1hqKgIoZSslh{MgXDkD(w43^rG zn_sg>c07&HHREVgE)Uflk&1(&uCHU%cVE;|R(G6ol&emR8Kt@hDo+GBcWjoomiEv{l~wOQ zu8yp(+q>>WclCx?8h_-M-Za9uH4TZvId&g({@Ap=Q4gyTZp>DH06nF3iXcwY6f$mw>M@n} zVq``?g<>mo@SQ|?d}?)&A}J3-9@|IKxR$j1p=SI`Eqcx3Oa)xOu&n)xB%=9_jj_)? z2{6V;VwP3C}`B!(i^k6n%A2?5*h3bZ$Sxt z6UH)v`io!511UR(#;sh)gFuK_27A}PCd1KvUr~MAP^GdRZd}-4H>>loRznt_2sa-W z(PQ1lkYoZ$e-J&CXzSCw!t1}~Jqa%ud1>h|>tel}adPvrfpc4-$4TeiPQDI0AWHtQ z{!(l>p0mJ0+iI`#2s8egig{2HB41w3_M$@0p3YpDeZ<6V&% z$+9E&M{+dQlUDG<&O3ZrbBOm_me9viV8~}@)_;;5#=AyF2r8jJix2>nVdiMsmBBc@ z&9x>Y@cC8K%9L4k%S$M7TT?0aiE3p^i3d$*7;}Qf7qpq!jlo85{DM82phvSktaS&2 zzXqzfjs~c2ak1~>LVnYNcobjCo;zs_41Y?PqPgme-gTA)N1bd**-!zyt>nuF#P&Yh zeAmr?A>k`)=B#@555-rFlJWN`a{LtwJCvug*9ndHLk(R*uE%FR+lyHvo54tN$Is6& zdx!gh#a2K5=nY32RsCeKU^0y?*r?Ot14i7UT%GZ_L+-^5G<(rQ_rGGUZsWQ8K+j29 z?Tr;dPgi6nLOAArmqnHP!)Q%jjRf1l6fvLOVEIr25ByzU!V_&T4Oiw@!usbSNDr=p zzLoFR3A9c!+)AQ6v2srY3H%q_l1-Cjm|fbTVc&tQ>;;_Fnq(EXL;pcsE=GO&is{zg53_a^F;3`a?%_D#9kV zdIUYRp#NSu7)g9J%Ggdx5t4QbweFq0PYB)bxEMlIZnfU+*qCyj(a)4_;>_sA*P|%# zVcG9ZTX*7ak=sWIxvo%SQ#(xvz55_JK-{gwfFbFSK~2W zdZL6$1hA`Lr;!i!3n1K1OmVxh4XYaW7l!9an!efU2mQ{=pN=2i-VNg*QMx~jW}n=< zq-{RM3IfTxsx&%O8*82jo0<@xi)#+DK7-A>+_YX|^WRFzw*nUGfGX9-uTxIc{H}C` zM_oceUPe7zr*5;jtRTC4W9T4i55R>b zmDhRN{la)Cx;Zz^{)Bhg0vmI^kU?(&%V>x5j8DAK?FD@0`x^})w8Rf#amih!fYw0j z5=+L|sT*XEH5=Jg5|4OeNfi>nw4=b4)Bz)&XII3N3md~Hons2=aj#oxSyIDQ#gHuv zKId1UbHvnes;J|9D@N{z6dTXh*qlXQ6OogZ`tDum5Z4ds(G5ON9D0_G7-0{&QslUv z*|~LfdpS4sjO|)dY{G^xnV9B?{E9LA*m{@y1My3!mT4`Mp3fMM@O_WF7cY4NagT;? zV$yEgLee4At$hY7wN$iL+Z?0UcgS4wG4e3Rr}P>pSHq`pDZ%4h_b8em>P-BegIs+* za!LzMcMbpDdB#({s7qJ3&!lPeUEsm1dq()eoum=8@+R%T9*HnQyfgX?3qfi%BNoYz zuU?uD^H`t>Xx%M?krZ*Ao-V@feL(AdANE36oke{6C9CshdnNHX>mYZ+`*dPW#HPzI zn)EngQD1Hjz8TY}S2&c#bPe&rJFlm9zO>A=cOx%#ugrZT#{D|oHC)Wz@FnVLq-^w? z*>hr1MX`6DOhR@GVBfo>C>UIBU6{+3YM3tV;+5%UZ`5V@d~n-Pi#5O90-5;B>&j+r zha)^dHln|jmYz1cnccl)I6=FTU@+vtPzet|jcsapvW6GxG~F_W<;EHM=k&qH_Utk3 zBdL1Lkx{(vE5}Mmmauq;@3^oTEqaz`-s-FttT3w?HC|7+`0QPJf9%M%dRe^Uaky=^ z883B%ZCbm(#V1F&U&b8oym{+>zqo<(+4ZtQxYU7qd$~N>!AVDZHFb@ELb z;}HOs1}oIF(JQF__KRrIZ{KVg_OvpSB)NN3|!|UFNgCaWi>}=ooEI1=w1$6`%rN*Q^^WE3k4Uc~Hf!p17wJ^C| z1xOGGfO)-yR?h+?FbPsjMii6K^*@nAV@t3VjAH#y4L#Nm0hoc3VkRE{BmTB{qt%>X zhm&Oll>-++0h8eTQV-J+L26=&Rt34<|FdSxGA0^BvzBAUPV0ZFyEQ4Hvw;HuoH}37 zfB3WoC>vJNz8)PRsC^;fqp_k=)#-;JyQ+lNLd2+sx*L1weo{?Q4$I~qYXAW*hFkIZ z?1p>F@>p5idBvD1o%8h{wvQF`PJabVHl$WT<`BN`DbjDkJgV{e@3Cb}bUG^86Ov@n%cep6!y}KA}5os%A zX!O>1(RY{s*3Q#smQw$=Opcm!aU~?!(z`8Z$4QK4vG&uz(IwQC>DDvwELN;DiAgsE zljr#FSpddW?O#?5X&f&W{3vjLm?qXAj2q?S|3=7`Ruk3`um27^G@G0+&ku8!Cw|}D z2I-L6Epex=Er=oHC+0ErB-C00jAzz3%;mn;54NoA$iS&-G*1@0WQGJUa(A^c5B&+c zYkbdMa<-KFi-o`NwR|awF*dE6?fgXrbs_0MtuA%V*7NVV4SiO*)|hIWS~+k>k=UxL^^Eqv?q6DO-|Jb{dizfYtFO2hH0>g}b$%Y_Ikt6Xw1dlhm5xQ#V%P5ADUj@^{wcP-3qXgQu% z{BaeuL7Nft!gtM1*JD1+tkCHjEuFbi z1eb)y&kka(Va3%TW}V!W#YfgGP;S$F{G88`$#^%KEF z_1MHr6IafjRvFatxub0dm*)Q#kxLiG+bdL>@#)W?ba%&waI0n@?vm&-84s{iO2dDU zTUXMyjnpd8LBC_Putd~JmzoD5nWVZf>!PTYHF{?hW6eX4@k7|`-Q`?_$SXdtTh+zD z$sp@YQQ~6j!c(zvhk>g@?g~A=-^eJ}zNd^8ze=ds-d^9di>dMl8D#VEx{B`U;d>R& zmf$+dXeLY&tdwZEvugU}HCV%UXS_J94Rz_`q&L$xpL^Brv6>unh*mKakN=ht)N=!NUrfyVN(dr$v+cc;38y?~uPhW%Kcxw5a3^M`azTTqC#y zR|{D$j4YjDBxHRj@MhDEL08K+Cv!(MZe`VVC~svSwKc~693HZN_r0fDicigS@vu*= z*A-f4U|b#NTFf;Ix6zEIpv*ia5NI1t4NzHz4f`ahI~)2Axb3qk_1#W4y7DDBddVl} zQtUo(lH00RKi1XG$$+Q*wHvyM(S|1Kl|zGrdn?rGuXs=$yI8yKO{(#k#fV9+;5r%iAXF>RRoC6(bPt=2>bR8}V8%&w(b$6l#ezwvibY2uf=4o3P>V$54x zVc)pFwM-Nk)H99wIR@&~1f;9OyQsdf7qw$Pi z8Ob0jiTbKKVooNBC+-9ltq>yGZzNKac&W|>6Sp}dm9xH&@l<8ITm0iW@Kd}+C#FBX z?$Q)eGA_$|*TfmMY|9 zr)2<}k$RhpjoI8Ti1FZ8`F(wtFJCeCQlUGi zB|EAiCARn_dV56b)R8VGGE|9n`fxV>A>~ax>zd;#>N4P4wjg@<>-=>gfd{dyrcoF| zsfE7;qKcbJ5X*ws*EE{ebe&A>xHVVDkJ=Y>k&t$&aiK`pic5ApsTeW9l3&=k1pm<<($XR*)h5k3>j}5Ai zq!96X^k>%yhm=t$$G+%ZM1e;fG&lU3{nyML$yg%YxielY-OoNOM<*RxQ0bQfHI1Fq zd*RVE-x0L7&ucBTba&K-Op{xS(i3+bX|?x9+x|$mpqB1j+Ld++RI#>NEWlB#t7G%) z>`ZO;=E2fm&N2;yIN>L4Y7WouaZbEk!UE$GIaV_2w0hoQeAUoT-DjGcs^6!`740=| zEwpBP86&~Cu>GPF5&0~e8EoU`8;5fuPd2D9qrej&-y(z+Y9Uf3Yub5{(e4J|EdR9G zbO9}#IckSUZ~7emEdr}fS2cLUDW1Mss?XwM-l-Gm%y!leIxZ=c=X>As`;~y^R@7)6 znW8qHg;F%t$jW;6#E$};ou3g?LL&VWHJWlMlA90wus)GN`vH9)I8bcz>`Cr68cRTT zyzpN$o~^@iljG$!JNhb2A2_SJ>`9@|+UuU93eBnq#j*@hh#O1%JqjnEDwN_no4BY# z5<^NHDmA+!Zf=mM!zL^Pwbdpn#j5{6h_~vLu;~{&(RUxCRHK}F+B43|50Vo6;<(i- zk6VASF{Dd=jJxIQE<3R}ARky~&<0+a`9Qgsuu2Smjfz}q!j9tuYKc7YQ)zo2sCJJdCg*`#9*^$|v(+UpMjfgcI#2Vv+#D5zIeam5ej3JHj;&lG2IWJovMlTZ_LR& zm2_&wYx$EKVD@F*LA;mx&AX_S^U_Ph=ir(Uiqy3bc9_~Mx9lg)2UPK8YJ7ULR^M9| zm-MnKZX+JRJX_9qU4;CEh1tx0NTNlS!(L#)JmfCDW??Y%(q+##1eCtfSw{&%=PocK;U^s(u zyIc6eVW7Dt91a#I{J3} zYarEAHy^(|Vnu2(a_VrjozDy7@=-sF-7x1_EH0X=Kx!xOVyy5Tp~I z#d0AN*Pa2qb_GQuVzv0K6bwn(^Q4`qC!{RlLvW- zAe7zSiMqfu{v3z~yOC$gR(i4i)MR~wT$+wa_yP-hjZ1Jn;jM2BG0mwBsV_I$_Bkp! z1*J>EnA+d?Pf8h-=^yz;5Ae0;EZkp%>v~q~+YE(Z#OspoUN!g= zf&ksPYn*K70lXc2J(D@VchIJ4?c~}!PIBP$4~KDD4*Q6gtIu;Osg2CysY{@qR?TF6 zhw8~%Lx+}M;(jZ8*%h9EfyX?s2F_E(&X!KS@=nnXtBz zUV|ITCcE+aW>-D+`igRhWAwYKu4m03P#!NmDd?||@vNxs*kF)MlCxN3M|Ofj)C)Ih zaMzxrs|eY|QdXVYtIBuITLP^{k71EV8E=t@XI-C>}Xg~*De(X(S)nCUrpSR_~f+z08PmL{o_=sO0tgeW5r?3t-Mqrhu6ZF z_O=-ksKth)x}G$aAk&&cH!^Tw8knwF1@;# z05)vYm2U(kM2EDeaQ8LMMm+VoX3SPEtII%){WtvE{EzStnzw8ImBvdQs^C1P)hnDu zTIkSBhR%56RY%SWm0QT37bXQ)z7cGp`)yYmJt z+#RM%(eS!A31?j{q`;w?WK3|Vik<(GGfz*x_xeQC^r%UUyWhgd5Vdt1OU(CN0fR~UWcLbydhR@1!# z`du~a_L*ClvLkB7=kV@SN6+??HDO9BT_nY)FiWHo8p_&OtW=ofTEiG_$MXjAbTWgS zYqN)kBp6lPv%?8D1D|cMV-C^A6Z#AZxxJh{Wb`A53P#GElZnwpK|K&D0Ya~3~D(UrlrAkDE5-XHy zCdwbg;dK8B>N(IbavppIn%vkFd2r)6yne5Q@(AM)724{O0IM=Ub7TELHqzNt(58fW zjr=hsVZFF{RI&WP$JY*TQJ3nrE}=7av_NA_W=C99RP=>?k+bxsNyD;zlE79^HlNZ` zzX{U_*;suVM|r;f)I|OCf4!p?I?stOHDz-5+sgV2v<98_kT%Oiw?g4D2AE-5CRj7? z=^=ks!WnjUvl1tiyhEz-NP(5BD-D|aQjc(Ib>KkcGsf{X$u{zH>WTePOP*R*C`{F6 zg;uxk*|Pa|haj80f2rTvekWvY*=@ljgb*pG1m5izwN?^fNgp-UT-0S0$-L?4s~(}6 zpOggB<{1!**boq3`Lq09le{s?ByRLO1f}R`vHU)LFlboV{Q-nna0E1LTiJOmHS`an z8Jas!Eiocsb8-9qv~YdqdsnWQ&7L=DB)G2w-U)OuGd#+dz+;vr(VKmc|M3YsNfw1& zk{F6fv#6wIX4_-B@)mG?omtiEY9W%@N0No(dfy(}D!V;RIec{FCvv7Ydo=E_9je^3#-6oK@hL z;h;J0MD?8^7l)Cp^`*fGB0axoRC``Ecl$)K-!W|-z`vOt_+dFg!zZ7`U^XlkT_c(a zavYf<>2_@?rSJl#=nt4uI-`AJ2#Q-!+_8Q7b zC_2>jy_-T_Gc`Tfw7>t9Ge(0HG2PCDqu+(XM!?5xK25DQDIzk3O~36*B&bABKXj#fD`TvK!P^ofVtdoY74OH1nCt!4=-rIQv; zQQPi&!8l4}!9A+b%t$`&z(#{+vmrQ_c@ok%uYU^MF_msyT_lkA8|)lUk~v$DHOG8rgK z<4dZiIb$W~A314h-=|Ob=Qt}_=H&@CTMJ}h<9l0{V11Yh^_DFx-8HRXagTaLT&fWc zy5tp=DI9PTCWCE843l=}Tp(O%8VW68El&h~y5vzFWL3$su zDx*%yWdG3enf1t};)|cEuEFdh9=>e%ayg9=3#-bLM5>KtyY;{`h;JYnzyU0~DLp1I zg8MEP`IGGN@zYnNnf2&*!AkKhjeXqJjoYOa;!OE<{K`;Ijp28zsaw$S1Uk?DmOb9c z9}0_n(ZvM{bUeMnph7u{Kn0S)#7eZc9eKX`pJWTJA+`e2#kAeT&eh%Lken@VB&*c% z?@@=?9xg2Q6qnka<-{r7sdzD8lDZWyR|GRLUE!Exd3JwfagjcBG*4Boh#8o#UxR#x z^K{{SUXMYSfDw3|`ZerO6vi`6lVGx?{ae)35jYnK;)U7C>AufZ3|_X~zM^bwLaW*E zeGf%LlNR_(6{_g6w6@Jpo{X>=7hvji?OAgW>^L8Ph%K%CG8;YnCQUq@Cpw%Ya@vr>*5t&oZuU}$jmF^@JoBKSuAK>z?yEb#FMbF zRjH|-r@Js8Yot1&h*%c!)1|c1u^*R*#wSVnfT1TDIC5GltS$UAZ0fxY9ydpQrej}# zEFVXGkA6JUXH?vXl2K68vd5T4LNmDsxwz0OhwPfxZkIfTOb^kPp86=QS&s9^wZ8wD zhp5@{Z0GXG2b(X+w#sAg?~%37Va9{-diTFu<$?-kcQmU%cxCQo>94QnbUB#RyhaoY z=nQSrrUtcu=ACS5wdVae>jZFbADKdfWF4zD-Gg4=xVYb)=;t}=Z7Mt%h%s{GlVpsA zcdZS3DHi+;6n7meh@RwZlYVUJ=G(tpDXzKaJV(d^v=aN?lc$?XR)`Vb?@`11{hLqK zF5iCd!e7rGJUH$xIUh*qHUm5zu3x9XX@^{c( zG5py4XrSyl=zrLk*gyMnlihry>S?D+P4~p`Z{BvPZw?=sscv~K-g}s8b-!5k)%b+- z&_x`p6E`13e+24fVL3&n>$+y-7KvnV{O-g%A_rx8+?6^I6pH2)CRMG^;MJ|IvLtBk zCRObod`7EezV6zZapcu|siUsMKLaP_6mEo;zg_SE1%`vD+KPu+fb04v#+y$snwI-p zE689jcgJ@oIf#DeN(!;#C-9Jmk)Wfx7*{>|ffi0`5YI5Yf;MzE45U3%{`fw@B`$P? zLk0AINnq?r=yA{K<%>#PL@Nwr76f~)xtG%FR9Pwub|1bvf{$*wSmFM)-A#CC0F608 z#L9htJ{GWx2|kQwg)4Sv&`%IAk5~CJNTKRnuXHTHT%Q@>2wq33UKMv06m=fdHx9R`!TmQioEVG#t_G@m~`=d`3sL$s4 zW{MKDzFDnArNT56@pVIbENa_Rfen@6I@c zNicYbW8~^2fcw3;kUpV#`|ya+H|;n1J6e5ASMeijIMEDX6;#SR-~NxS73yr1!1hFs z?oaC>+VS-INv1mMo(shQtF+g;b8*@WQWGrj&aRR~gUK20+*9?bX+=1iXu^-O;$4oH z+2a9keCEbCjs`Yp`ZFr^GDF?-`bfBidpAg^uikQL6nl&7OyWmz)wmzhSMe}u#$Gv- zeCsA*tK1Rq^eAyt%%JdC(UhsIPLO|&PhRz$9gm!(-%hahnu;*%yOYoHqe_86uwkR^ z-uR9Fj-SA9upn`+_V)~EY7SSYr?!gOZ=c|G_Ahd2ZgNu)O2}|Z2=18O{k)#;I3{^I z7h+MI6|PbxPf_e+-%NA-bhXf02Co3#uHctC?5g`P^|>2ifZ*H49w(oGv%t$O+b>bv zflWVpix`~bGzS!Qv~&n0$cm zz8q{_`^UJWxz?f9i@EeJG(TFEd8vAD&Kx1-J3Z2+B)05a9w>QG?;W|_IW||v9Xt88 z+a!i)a|aZuct{oye50ibuA4SZFsxoK>(Y8K#gsHeq}`eFLuqN?BrkgXF{O$Rn>nGV z;Wcx8)r1M=PVlvzd_+XUYPhu8hqrL&)7l|U(WoDqc~j5l?&ek9S5mGIJ7TY#~L$8UHv+8XV=)~-jifO*JyuUL+;6#WSGmT$L9#*9A-d2vdX?C~;umD;{ITQ#>C zmgp`Ken*TZz)bR|M=^tj8zN>*FQt0pr;s$<&Ruq90cnE0p<|zimbcxuT$tk1{(t)9 z^q-BQ6mB&^H|@%!A2T?(0 z%$cm_RBfd33CF%H+C$;y$I{-65uKW42My~hnsaaDdUl~huKNi*f$Vj<5(&#FaN4^>9Lq*OP@ zPTmJ}1@;cu2#wyDcnQtGp<=+5t|x$m_8N6@eAp!U&(9}V&N$0;gIYZ9nMPp;V}t`hrSHCn8MygAnv!JQx9o5}JV0hQB9|UGzQ=O)vnuqZ0(!B3 zix&I5|8hQgX8X}_!q`-)?D2bglCPj=;g}=ZxWI#t_e$uRh`tq`y>V6PLQN3pK3cND z3th9npCF4;WQ_bwTd$DErs{MirooQBUj=J2f+ zrOQras)XEXG7qHEscaG7_vw|4p#wV89e9ZWlk;;1rXQG{0RYPCfBy?W4Vr2+E4=+w z=xR8-`@VdQuM=6eC-?YgypG*JhT+EH>7hqs$H*E5QYY_4%bQO7US9FXtt#WQvAI7$;q8EZ>`*__;_m%I#xq!) zm}c$|YTLe{H~Q`uPDodRz5Vo^_RR4q0}?SMpTCE907M+_6E-Ir{U}3l-fuDsh~fSH zs3G_e&0AK(K@Xa@h$r}YcDXl$Iaeim-q-f*-h($tlcP7}IQf*&u)dd6%aXGrUr3sP4w+Q$TazxlRxLO1#|8MVvd~lk9w7Pnhu!M z83X>0Zm#HqeiqL5uG7K5S`IGA4IeWqK-B}bTK-E6g3PJ zM)VqH)FHYkck;R4``mxwKKJ}^p7X;wXYaN4`@CyEYp?Y_ClOC$`Wj5u;&UHu9Yn(I zVUSpHdl!@+3}Mnd8|lXjiC*rR$D$i6n~zttFER-EFQ|@8pG}ZBKBye5XcFcE#O-l8 zN*l9ghCYh}gy0S}rWm{DpQzI3lC)crSEKrQJP4||xT zg({B{D1EhqX4cE7;d;V7PV&Mb!rY$ru8^)7b+7f;sQuX5_ilpkwNW-68QO9HOd?^5 zLnXWlntn(Vjzm(geqX|-rm`ux82W|2H#)2LJ;ySqIrZ>ahT;IT@^k)9GX~*p*#ci?a+YT$XE>Y%y*RYBRd^DG+$@4VL8xlo6TJ#3hgwW^|N?L zk{Ro%lOr0PwYoPYy`WMxiJIYUYh9tzYAy;FB`>EBG8e~c``Fd+xI_~y8);%#+k-j zFyhD-EN@w4Roa_U|JwApW_#w)&DuYa8xOw=`q~Md=6=NT(|&K@1Z;|;y@(Ni2d3}g zdsgCYSGl=^q6j&5$Ck0i^SFuGcyRlX!3MO13w(3yn6EONVi}xx1TeztwOSYx@0< z3U0b?P8{Cr%(NjLi$WZ{W7%VR?f26!oJg`n20eEkw;F=J73l?FSC4I^TF|nzw?uxc zB#|?NtW(n;%6)B*+2<3x(-Z+W(8Y*$X*=mKWOna}^N<6sn!by)&|}b!VxM_T`hEON zj|@ME@^}>))>EgUo8N+VZ&C0uxRXn1%TOKez4_(q%kbn2NJBF`zgy!%kN`W$1q}AS z%~r(OezH!w2KOS80Zz<13>Vuotenoo!&@G!Qfj05s1(6l)d!7Mao}x##f2XW5o=SE zTZ={i44sjw`zcP6eb0HAJ_GFaKjy4m*^Lt6=a~Rtz9P2GwUxIszH&YxU&uQ8=H5^# zv*W=jl(|I3`cC+6<34U*YXJGrGB_xBu2QR_ zE8A)W-g%#H`oX_;1YZor5PML|JpGJX$-@d9w3=@f8YVn4+on9o6lGxouzyj@zO+m7 zqLd_Wq3NG(4}4mSsko|skk=U!3&7l>O{z%Yt;52EvC(8=-TQKmlFWv(!{!YyN!(Z= zkzF_d<-ZHVxOVYuH?PM_`p&OhNc%UQQ%~NM%uQZOwMGt+;g1eCY@!HAi-XK1(-+I_ zis`HE(gGLfAi(=7K>j8nTCH?mn-wN@2Y(a%_(Dt7!SltPoSrcb9++_gMS|&AeDT`M z4UqdhVtvd`<}F{4qm~Qx+Yw=2ZPij_YiMSVKv~~NRy+u{Ox}YrWrd;R zPp2`e5lfg^ID>?NfRtqI~cC)KS|!Ar+`5WCE>$iXY(MRI!c1Ulf{xJa!u z<7_h)GA$dZzzB_G3^Gn*G=qO&%UE6{x?2g`N0FaxF^V`L%lNN zeLj<*4#qt0tTq9;CjB=!9y;{%Nm`@F-1P;f2&dBNXy@ntA z!pH?gq2U!Xcewzzt0=FEbRvco5S9CXG=ExgfMd{D3l*HK@~SXce}STFlEHM43KHMIw<^e=EPA-^3oBUTAKRZZg2(41|j?do8(_Jv5WFdq98{^N7&3*H~ zuPo$2cpM*|cv}RIoVH(b|0K4oCBbFI5#vE?91o&yPAC{VDXG8IoZvr-xhr(#ktHf>B&yU;ri;q-$5&FAd zd)%2UhLUm(H;bT)HW=~R0o@vFvz?@eYlI7atLF|LU3#EfWXXJ@SdqyYCXD>XwsrF$ z|H*y5^9?jD%`I<5|R-aGRp{u0{#Loj_W`eyT z@`u)ZoGr$Q3{JqtjF>CprAQf=fGVlYp2cf~AWJ4QV|Lg$yGrS#h->Xt3Rt!gzp}#@ zLH0I7Av1X5M zJEF)kKi}N8dVnkA@4eI4eL{Cgkr#9g$rtt`mdALXeQm5KKWVWyvXQdDTRD=DT#$O{ zMi7kEPrT44-6@*$Dn`HEwU>$W?G@7nMD6-F=YaJ zN6&c)EI;%QwX=%&TidsHB0f2me#M8%U?AYqVKk>g%1lq21Pn@VH{B8&rB4rkzU`_A zJ2$RZd6L%9=u~{(qkCzn=5V~1zOvEToGmIaK*6JA$QpLMQiJ4*W2b@}MRDZ4jvCog zeYc8)Xy|MW&nmQeRT}tv+mw#T@wgi8FI4%f9RY>NSA4|X0jBqL5P}k8Us`qYdn5}* zGl1_IZQhrd>0oqc`~*s6c#6@(fwQ)EbtL3gMIT4@9Y;xJOMm*T3Z zL1S#i;Mn-whR8IFs{l+oaqvA_PST12h_5L|Hu}A&NP2NBnKec=+zVx*S;MB>DCVkPK4uHU22|C1 z1`^Dl?qB5Wo->!me*ZI)=OPPRuyn4Qd}*k`p}2;tb=9iOO>jodGz*})Y+1V0xOk{7_U}4Woy5Js z5vm|Vy&UmP&^PWvC! z0IWG$b2-X#FNoniO?0%>wG4;Ga;W`}e&@+4`H$uJ*j<_BewW)@M#*x)_kGKb4%U*3 z;)JaqkA>aoxcnjFe)BstrNs{s7wog6A`#cCbD7AR%;Jva0D*SE5(+XV3?zR7-yFQ5 zL({M3H=Gue?y(H$-<78K!HVWuvpUs|cNfmkRoy#)Nj=lM=o)!CdKksSZNA~Z+A>HX zV{q^GY(GnU%Q|Fbb!v{yv7j{~e#mNAmZ5FINnCXnitX@bXH`}-`F=Tn-NMnWdd>85 zDX?4Jx85>`bH|Szv;eLfgH~Uza4dYDo9liW>|Wy?CJF-OHQAnoK8ha7a1Y1PL?3or z8jePMpByS7O3k@jxXelHGbXw7LVIBXr;`AFg#xtDl9{XL=X}}sf@oBGeQtZ}r{J(5 z^?wr!|4(k4E-yBp5Ibry71GIbIOgskia zy0#=~x0ICFArOiyg4GnCQLRH~lB}rOAo$#;GMtkm4E8mM=r*&&8QF$T*Q#QBG0cy; z@y5%s#Oz@J7pYyElO1}4ENVrggDMh?buJN6SlQk_2rMnht2nupc~C+E@;9dEv9`$H zoSHeM@u$M8>u@rT%hXmGrp3*fW(NEyY60{4 z)*XTL*x3p5draf0K~n5+PnrHQ@31)eeJh=(OR6);`o_qS$)lR)Xz=_Y^A(VP>u$=H zDz4Apu5hoZzpiLr!)!}P#Y17h8L?)ISeqJ=OHn$~3!6->ao9*5zpIAJ+WxV)ZGnk6 zioy&R%|nXyP(1DDYGqwVds_YCMR_x!@>PV`4@I&mO6=5;*6+n`JJQ_PHr9ErnEdXB zb|Fl#Ocbwl^YY?8*C>Wa*z;O6m4WmmAO&ptmKrX-N7Z2@#BX?zaxveeQ5BbZf4Iuh zl-AJFuLFREa&T|Xb{_u;Yw|k+>&xf$H6& zH|I5%56oG0g~z1SN|9<~!j6rC(>!g2uLo;aBVFKs7SB(Mx2%FtU(R>Xvmu1{8dvES zes0`ynUw4-GOw2fG`Q=d+l&^95hb+PUj6!crTk<_O4;#*^=$?giZ4d%Dke+rd`BI$ zogaO-rUxULLjh*r_v%U6_D9n)t3`$a0S&&PU%$^$A2k1fPG6`iu2;lMe>|}27@H`; z<=`s~cY`VfAC%42w&y2Ofj|ZAn6+%g_u0eptVXgZzO3+!tmk2{!yKAm0R2|P`6OVr z`cDh7byNM2Mbn`(l+lc-tkE^I-obSh;cXP_YKhvTQ4BHvprt4SO+KY2fCwIH&3;>lF=LZJ+#kw+~?}o0wlNNWeHn zi7X7DEU78fZ81OSr|^}h9tf`MS~oQue&pG*G4GL=)8e?SVaDqjKGh}_H~4hOzsJ96 zucHBMgvjg;j{~FoA`NfCJ@9)s=asEzT;mH3`(nx~u+qA{cO;zb$CT zz2RcdOg#6p8VPY9aPZA{=zMJF2|Ikj@!O$y?fS`V&YtmyaZi_L&Nvrh?ccgyrX-k) zNbdFt5ckbP?dLGMY!d0@QxWMnbU0gao+V*#iv~5#4DH)IO9t>*b_4-<0xSR~> zjfc30Az0uTov^caQc+>;_(8G8uiVzdeO^|cuqh#x8}Q!WO`Gi%!{;vOdDz~EICRvj z&kuAIonML&<(KX_!$MoMU_hdwugwu+SrD_PzSWTM4KDV&qdM_y>tQ?sIUaQS=+}Uz zIxg4^gaQNbG^GwGuh-Bd01&dI)tXE_>-6qEPeK_9U&xw0S z)1mSF>7+N{cN0F#r}L8RX}uKSaIkxzyPY zTw{F=J1LhOVPeBi_`m>E%kx=y5*TncM(#aTJPF{RgQG`(YFCf04aHe`D)9kua)J&- zPzNy@aQB2n+d{q68!Ue|%Oy4HJUW>%NA#7%B+rj;(qte|ZPmyx1A!^5L4gQ6TlO{A z-9v07ULn0reWfT4%|90sba#kOCBW3;__L4v+dHtnUzU}vB_6BxA*tR+OZ2Fdc!7W_ z|NY{;y^)@+ikavMRLy|i5_#>={b!N zUBwQ?d{r#o`eUo#|0J|6N<#J-;1CqSu^44B_)4;=b!JZ8zsNC;KO>}U%Fyh|*Fz%q zY9$N5O?dc4EPhhQhkdf`*6h9%{hZK8b?HOIPMSD?;G*GkK651wYS4kNlte^KV5o_Q zQ3!b2HzNl9fnNl9vDI~x;oOJf9t=fUwBC}7p^gz4HUa%R4$&(Ru!X`VyzBtogF z)rxUr#3X__K|zzauUaZXQ6~r0aHS`Zy0uE6(j}*X_v7OoOWsJXDWGp|pUz*-pEuT= zHktOHD}A3$Awh8X;;Lef^#w!h8=Vp%5#!HXY8IW#H4)Oj5I(& zQJ@PAQXPMI>BQ`AmxDJ#y%&=s+a*?j4MQmrGsfn8@ra2AZ|qk-lYYOi@V%Eoy7%j& zo(Cy_uwqxGWX+GaNR~O++HC_e?=K5k`*k{JDN~XbEfpjvM1*d2k#J#YuV@d%eqMgE ztMsH4e~R=*n+8;sach;u2+~Y@D$_^AAT3#d$*G!7LG`(^#S&dQb<>M1iAFK03A4RX zLe8Z)nJOg_gb_M2*=x6UePW0qZD?KoKw~`^kA_=F@LWjkMh1r$jee)yi!#f@^0hZB zlEL%*TBn^-<(T}>L>AEX`(5T9`ttUM&wlZ#CE|Y@)fTsWG7vd&wv6a%EB@siW@fHu z=_jBhBpk~7L_G~#4)m%deoEU(9L@K*qR{-Cr9W<+K3DI1 zzW9uiz^{oK59!=TzxbUx>S5MRuaCN?BO=L{DUWzr9v5^7TM#n;fo9fW%tI-8B&AH5 zD^&-PAJ0&*)@BC;ct)knxkJ445)_;0Ipc^W!l*ysQb6#95Kh}ZEMIeEi9))cbP>=NQ^mc;LoAZx3w@4HY2W%Ekt}8cojuvy8O8LJ{2Nu z2~3Q5=H5I0VpoJ0q4~h%>!s6ekFz60S%q7k&Va6TWVg+}0UEx#%HD zJm(bIs8hsP6h4%dw**yU3%;l5>Nf~1mT7K{FjSb7-YLezF34v1qBcs!su-`tvx<95 z5SbVJc_(MKqQ7F~q|A*?37mN)g4F+Zi#v%=HLlCBjlC(VBmN)|%b=#FwgxHlit3ej z?mUOuEjH@W6|e4)C&HEL#l;1d=ZJL6sl%;3LcZ>T!!JjK!AJyKClP&6uf|W?wE%>C zF_gwvoz3Lndnn*YvIAr-2|F31~KP-^^nD%qf!`9cLv=z4CSM>4&uf0@uzw9 zoIJ)a2b2_q{EGT%l(oeotGV&GcdPZ}D>RUZAe|7y94xS3R)Wrmm;O3x1g`JcQ90&eYDb?67RO zEU;|7%xOpl<17i3q9KV*mAlCy#*2)TeF7?^-=(9V*9AF7i9}U&6TaoOBj%510TD&_ zei!VP?bhfX=x!j;4Poto;z{Bv=e|l%sZ>s8f-+LX>3yLbOW#&f$TWGip~9ShGO9Z2 zKFX`5rKPSVqGeRxu4P~Tr2Lmz+L&AZNp!A~eKy2w#T7YEc|*wtsDM9)I}RvAMR*IzE%-thiqzBDbI@`dU9zzo1F;*8j%nL1(dv zEwM+ZP$yw0lT0AuQ1iTxMU=6!NpWxHSmuoKf~~(njDfE~{E|VN)8o!^BfBL2AD@0S z{2=?G^!~?#5)?EPR?^p^n?0GQGVjCv!u(}E$<&2^BlF}kAqgZkC1dBc=5Dm{OW{ij z<4k&2I=>nxH}U3ui`V<}_wp$F6dqj!&m6hJpQc&YP90~PM<&&1Rws>G7EYm+vDxRk zM!6=OKRKdZPa}L7ihxnl@g(#kp?B#+O-psGuYQg(V^-$xNDMv~&%T{{H)UaL6K|&W zwqj!sTuki)?$ltcWaxs z0~PG$MP*GJV$P@ziOb3>wtdl?o4bj-)%~zi{O#2xI=e4+wX0zQ?gF7{6Z}<}pocIL z8WNSKtGO6`0lP8#DjSEkjP_=ugV|Z(lKNO>BnbkR=fzLk8f)FE*Q>1|4T3t}XZcIg zZ7G3GPWE;yb!s)b_IY)IH3LpIcHYlgUHxs_FL0}bh$%k`6S|bUc)*Si<6Otxo!q8e zKDny7&mHp|M4agDc#a1y;_p12*@zmD)mK^&T4-qWzN|SjzT7=<7a8`-v0Y7wj=V0s za=l5pnz;u?G)E-6H+_%wo~!RO-$=iL_sHVf@6$^trZjibcAzcaT1pr1we0gZrY5Bt zfxypQo|`|n$oDccG&A0O&+)bRM{#ZOo^9m8)>0P@DsD7xFRis*U$uudYn6N4M1Imo zMVVom6+xUcm0Ok5)p9;)w>47loQnGY>jQrd0=^C-Ud)VFMct|bWHRON2K>)02~by8WFWOHpydDe$BRxXWt&b ztf7gkNme><+V$3^cdu8je=1GBU!hl+aR~ZWUQv-JLx-bAVVi|Dx>5<2R_gYmibbVT zEux#DJLT}<;)m<(R&h>!7>6iz)05k_(VWkh=*Q@E_lffO6|}i`H4VT^MI*4St1Z^2 zET%uwV78Cl*K;+y3yw8e%L+}22KEy1MNBVswr6*0ya{Ru3mM%6*%*Sz7it`;D_SsB^&1yD!e4 z7s^v=>MXG*KTaNP*qArXO_J4A8E2d}UR+mRe#Pd%isPZi93ibGlMdfiU{bI`k)^OS z|79U^a5=b8MNumB+HvyWV3>B4wnO$Jf{=2T|FQ76qtMaWN`f4#vr?EaWOp?&wlI%I zDNUHd>7t$FSJFq*>j6rE4fnl8*Zre#A|ZBeo#SekMeImXta7(X9-YJ5QHQAwJNudL zN?Hx1BJw6uyOZN*dleWHAB(Eyp4UTuuAimsRv}lVFZ9=3Z!6xU&DYuQ;qJxHPc-P? zG#`uiHId&|)XkM$AGAdU5>a)C)?Oywo^{}##|}_*C~YbAW@rk1_1yb)rECh`SQG8K zo`OkSWLJG%Wp8NuqAyTCd+R*7KvdV|pKE82TS3S%#ZBP}B718j3Tn%46JN((uINK<~q|~Wub)SQ8Fzg|Mp3VD9e*y$z z=+ccr>P2cEo|Gq#8t5RS_<|)LPYGdrNufq}gZ$nbY;q@iYF-a@>oI&kgzY^M4sMzO zTW3}Kp~c|9gRG+ca1w+Z6NJX@iwn1jlM~M=q}T?`<`SmuqfaV92bRU0&x5~_p{@H+ ztu7!$`p6u~FBt%dg^Mv*&O|{0;R$e!if|th58)ngg$VpbKqN)D|JOAF!V5&Q|G8E{ zWc;@c5&}Y?IRf&(ZM1;z@IO(&7jXB#zawQL{m0^dbLPGOTq7L7O$#yjR)BA4w$C-~ z5fBLJ;a`YyDs;eyNDs_kgB`#MF9nQjtk?|R+87$Mxmel4??MoA5dbc&j2#T9U92pv z?FC$fY5uYh0IuP`W~ZV4%f!J#m`RR6<}v~c6MfSe#&NJXUfjW&(F`!!NtzS#R^!k+Phji7`U)n+tdE*A^&-f zl(D^$ow==pxs5e7{J92(HjWO$G&JxR{m-9&wbQ}e{O-Ta6M{cQK-t{I*b*#d zZe?t355I?thl@{${kI?e_EydR-pa|t!~OSL|Mt&AqhVn@gB`>wJ{Dx>v56VQ;dR zU-k9eZapSTT734 z|G;{xkmto8j0l=3?)|O}|8ChJD;lGZbFX#9t3McJBJ2_WrW^n1oUgT<7-GG))7S8r z|J~RB7$M%b?fS!~Xb$p7=!^OBs+qk*{2(9VK;|4 zlR)tKYOGT3oX zGEFJs;o^3=TSdDi)oS86{i1ysz4d^^G&QamOJfY zg7mE0DuNH1R?RYQu|SlF936GnQYT|epp(Y1S0()Hq+#N%YA)3qLB>|S}rcD z56{<}pMUqYaCqK*Kh5ozrKQR_@j0}L`F@x-$;_bHvxpN8nlo*i1~uHBuPZUw=K=Jb zGyZ1xWz=`|cW z?Tdu7Eqv@RHuQW8+M@|UQKc!v3N<4-VbCj2;S1XJco)!gd%eGfB6=o%@m)}SP|g1!e#`jb+ATV94&@_oz05S~cWalQnRv&Hv1uSc8IYf!I> zFZ*n~R6moQzvP{BFb{a7-t8L8HXT77VJrkXWQAUSXUJIPQBvj5HOmSZ_QPOHT#@k@ z_PBy|o#S6Vx4F}iO=F{q*0{t1aVLl znRT^+gylmR&eAV-?{oQ!b>60=z1pAOSeC8J`glGoWr%DgTYQt#_c}M$@;YA|F-fsX z$W1ay-VwNuvB+9A%Y`vnEh&CbzY-x>I$66M!koMBu_1^C;p@S^5_abfS--uQXd2eC zD2xwSkfn6x(|#zc!!m+ zbdwnzU;Hd8s;1R+98(+VB(q7K!7ApI&`@l%B~32_j27E>Em4x(heQ~_9Z{tL-v~07>7B>3F9od$59f!7>X>VcQ+7B z50Rzg*Sl&_Lt9xs9#I-tv#FYMs?jT_K+F)p>n6fD`TDK)i6~vOU8)CE+q#CupSIfw zrcfi4IAsjg<&x~wU4;P)jvcfei*inTwqG%!SJTi!v%RKr*MXUMg)GpHB*bD)<+ho{ zZT49lZHWlOh@}9H+#A+GGy?0Qg5u=j>Mj7@lZB9$2M>n;H&WkaDS$jEnxD;c*}rfmG}n~<@57C(yRr`9j?d9&FrKYokvc2vh{p3pQ+ zW3kLo9*qpd_TN569Rl~;)N~MTeIT>$KFOQqop+(_dpaPbnd-F~Eo-NBftY^K)qsXg z<^^;|qy5HiUZ@`MN;lC|c+_6d8MvF`uy0RJ=3a$N8U%j&7%3u<=J{(XX#o+1Jc>$7 znM2}N3kp?gz-g?a0Mk)hJi7Wt(88LXfqy(7n?^T&$;~II-V4vmUwuYMY%Nffd&ji9 zq5xP{_LIWj{sJndKa?l5dUkW#l<}?cVwC98gCu7cL>%DrXnDJ>77h@ae31v*o=~X>P*NpaGAY>wRxiki%NMM!zw&gN#fqw-c&qlH`BFdD8sObFtZX>O$};ZsLn%f6g(=*SE{Bu*N4E+^Y)eBnUcblAs3G zuTW>J?*|8BR7xUorb#!6nuQd2#v z9Xk0A`1=G4a$}VRTPCg<%d$129Z5^?gBFxBM{dI9W6Vn>k@MB7H}`ryDR~CfDYXu0 zAd)F zIQP$^J{Bt0OE9KB%7kpIWAR+Z_*qa^Dv!sKM;k^W{5Z6F)S~a%_zyO@ zVm<~bDr!_(nw6gQt-Or>oBE}0o)elMB9}X^aw52lP#<|Rq^^VWK4R*9dG-eG(9Y3V zA2LFg(j}5T6`W?%Wb<5))IbW{WyJf0m;QD&mbA6BwkuyAFdw&cw4qT(9lW9MR5`;l z^&UlRN%pZIME3Bvr4;a2a`SiglJj{cg2?QQl&~aA;rRMnmk;8-!^StUyjOQdoG&?% zcG-Mr8JFK7c~661Hi_TRt5t);~3dvK&! z*mK2&_7a>BS8Cs9&qO95Oz#7pVsjL)%g}X(BnKiL0}f4SvEn7DQq_AK3!C@=#ExwH zE1*I&VHSL$s!vHn?N9s0$XFo=(khUOW`Id$^<6Mj)Uu0{WxVYPnf%ECGvzJ@D7Czp zn%X5W!26u<+Gp(&PoCvfa2L8)o8+5~7BrZdDB|M>cja<#dT`CSTdeX9ajDS2U54VJ zWSFzIi>FESgbUb02VxQLIl`#Js)KEVP(5uxr5{c>mO*}Yno?3ZtTwT1$o2`A_%v4Y z05`QF+(p5@Z%P3p^K}Cbxvw6!j()@;WCTdAABvNm3A|l`X$cpDnhT6P!!QV>wDhu3 zQS|ENv~fLP>=f2oG?ClJ9PMr-pla4--jkgAH}_BRm4rCwfS^8!XjuSKIp;Lv--}

6|E3N=pln&~pL^%3fIF9r+b z(r>_aa;I!S_|BI!S8=U?FWQ;PpOO!a#O5(U`+Uk?i0Gseb^i>QEiZ`e9@b;m3UZi zC^?d~S9c@|=GFGnfcK4khqr6QBGsMa9)fG8fheQ}0fJ8xjMd_5OisMph5Av*=3o}u z?RZd2Js(aqL3EijNQWj459diqXGA&bSJbkga@-)Ygu3cU)GFe3kaf`a_6?WSKAtWd z%MyXkC$8~o>fa?e)?h8@#9xGm0K3aaMa`1_UusnTzb^F-+rg6eam zr8;c5*{$0(j`=rIV|72q6(-SU9CArn6l|0vV!h)31zj1}mfh)Ca6*Z#ti>>mXJvtm*%cY0Gt0qaUAJ4Q!`3Rm{<4FC&l0Vi70F66C--_M zFOumVjLPB=9wRnomg+YF!Dw=Ib=L0F9~_d??)wd8O_13}92Z;$U!rWgt7(g(zGczI zpG$!VUMu0e>o9q3oNXY!9${%5QI}w4JNNOvE2;MVE|DnSD1dg~~Y$JRPdhgQLhC``7IB|xYr@z7{JpS>__Nrzhy*J^~xM?ZQ zH(qqd6;*N``6_zkbf;?#-Q0x{|6Hc#nBh7C`=}^{vr;EoHfSa%&$>L`>ysy_Q8ra4 z@ekvym^pXXY-S>H#NWHuy!R)5Cux%! zJJu!I3G$%ZR_Dg-Bv!JHwez`)#e_w?rUlh`=M7j!b8M!hX}t7v^_tPziJeG^Xu_IN z!NiO{MbW%d!!hvV$uMt)x5_Y2d{Nh(vpB9Ac7Kly8*xgI^wx?<@61OtU5cQ%PD)7+JP!vjuVYbgNt zB6G}DxHJ9)j9|zF&0S@-3U{R(Kt5WF3kUK>lX#^6VAP4Pj6gNe`s^-;2!vIeGQhj) zUYSl4{K1G=Net0L2xH=|`2>KeOfp;mN0Ui2SN((08zG?4FczKIyJGMEKS2L41C;6P zUiB#}3lvVy&vmjn^s%9gNAwS~xA_LitiHkRv_bh2pyZX5~1rBxY7 zCxt47%?RJUYz26ION_d5Z>}%%0AQ@dUZebe#m`sy=a{TPrhi&CQDRV<%p@o1HXAeZ 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

YiJ+s3~=4HZ| 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 literal 0 HcmV?d00001 diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md index 1d412174a7b..9e2aa602767 100644 --- a/doc/administration/pages/index.md +++ b/doc/administration/pages/index.md @@ -204,6 +204,7 @@ control over how the Pages daemon runs and serves content in your environment. | `external_https` | Configure Pages to bind to one or more secondary IP addresses, serving HTTPS requests. Multiple addresses can be given as an array, along with exact ports, for example `['1.2.3.4', '1.2.3.5:8063']`. Sets value for `listen_https`. | `gitlab_client_http_timeout` | GitLab API HTTP client connection timeout in seconds (default: 10s). | `gitlab_client_jwt_expiry` | JWT Token expiry time in seconds (default: 30s). +| `domain_config_source` | Domain configuration source (default: `disk`) | `gitlab_id` | The OAuth application public ID. Leave blank to automatically fill when Pages authenticates with GitLab. | `gitlab_secret` | The OAuth application secret. Leave blank to automatically fill when Pages authenticates with GitLab. | `gitlab_server` | Server to use for authentication when access control is enabled; defaults to GitLab `external_url`. @@ -601,6 +602,43 @@ configuring a load balancer to work at the IP level, and so on. If you wish to set up GitLab Pages on multiple servers, perform the above procedure for each Pages server. +## Domain source configuration + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217912) in GitLab 13.3. + +GitLab Pages can use different sources to get domain configuration. +The default value is `nil`; however, GitLab Pages will default to `disk`. + + ```ruby + gitlab_pages['domain_config_source'] = nil + ``` + +You can specify `gitlab` to enable [API-based configuration](#gitlab-api-based-configuration). + +For more details see this [blog post](https://about.gitlab.com/blog/2020/08/03/how-gitlab-pages-uses-the-gitlab-api-to-serve-content/). + +### GitLab API-based configuration + +GitLab Pages can use an API-based configuration. This replaces disk source configuration, which +was used prior to GitLab 13.0. Follow these steps to enable it: + +1. Add the following to your `/etc/gitlab/gitlab.erb` file: + + ```ruby + gitlab_pages['domain_config_source'] = "gitlab" + ``` + +1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. + +If you encounter an issue, you can disable it by choosing `disk` or `nil`: + +```ruby +gitlab_pages['domain_config_source'] = nil +``` + +For other common issues, see the [troubleshooting section](#failed-to-connect-to-the-internal-gitlab-api) +or report an issue. + ## Backup GitLab Pages are part of the [regular backup](../../raketasks/backup_restore.md), so there is no separate backup to configure. @@ -696,3 +734,24 @@ date > /var/opt/gitlab/gitlab-rails/shared/pages/.update ``` If you've customized the Pages storage path, adjust the command above to use your custom path. + +### Failed to connect to the internal GitLab API + +If you have enabled [API-based configuration](#gitlab-api-based-configuration) and see the following error: + +```plaintext +ERRO[0010] Failed to connect to the internal GitLab API after 0.50s error="failed to connect to internal Pages API: HTTP status: 401" +``` + +If you are [Running GitLab Pages on a separate server](#running-gitlab-pages-on-a-separate-server) +you must copy the `/etc/gitlab/gitlab-secrets.json` file +from the **GitLab server** to the **Pages server** after upgrading to GitLab 13.3, +as described in that section. + +Other reasons may include network connectivity issues between your +**GitLab server** and your **Pages server** such as firewall configurations or closed ports. +For example, if there is a connection timeout: + +```plaintext +error="failed to connect to internal Pages API: Get \"https://gitlab.example.com:3000/api/v4/internal/pages/status\": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)" +``` diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index bc117d774d5..0b2afc3791f 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -3184,8 +3184,11 @@ stored on GitLab. If the expiry time is not defined, it defaults to the [instance wide setting](../../user/admin_area/settings/continuous_integration.md#default-artifacts-expiration-core-only) (30 days by default). -You can use the **Keep** button on the job page to override expiration and -keep artifacts forever. +To override the expiration time and keep artifacts forever: + +- Use the **Keep** button on the job page. +- Set the value of `expire_in` to `never`. [Available](https://gitlab.com/gitlab-org/gitlab/-/issues/22761) + in GitLab 13.3 and later. After their expiry, artifacts are deleted hourly by default (via a cron job), and are not accessible anymore. @@ -3200,6 +3203,7 @@ provided. Examples of valid values: - `6 mos 1 day` - `47 yrs 6 mos and 4d` - `3 weeks and 2 days` +- `never` To expire artifacts 1 week after being uploaded: diff --git a/doc/user/project/clusters/add_eks_clusters.md b/doc/user/project/clusters/add_eks_clusters.md index be4e9c28380..a1d957ce128 100644 --- a/doc/user/project/clusters/add_eks_clusters.md +++ b/doc/user/project/clusters/add_eks_clusters.md @@ -65,7 +65,7 @@ To create and add a new Kubernetes cluster to your project, group, or instance: 1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an EKS management IAM role. To do so, follow the [Amazon EKS cluster IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) instructions to create a IAM role suitable for managing the AWS EKS cluster's resources on your behalf. - In addition to the policies that guide suggests, you must also include the `AmazonEKSServicePolicy` + In addition to the policies that guide suggests, you must also include the `AmazonEKSClusterPolicy` policy for this role in order for GitLab to manage the EKS cluster correctly. 1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an IAM role: 1. From the left panel, select **Roles**. @@ -208,7 +208,7 @@ NOTE: **Note:** This role should be the role you created by following the [EKS cluster IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) guide. In addition to the policies that guide suggests, you must also include the -`AmazonEKSServicePolicy` policy for this role in order for GitLab to manage the EKS cluster correctly. +`AmazonEKSClusterPolicy` policy for this role in order for GitLab to manage the EKS cluster correctly. ## Existing EKS cluster diff --git a/lib/gitlab/ci/build/artifacts/expire_in_parser.rb b/lib/gitlab/ci/build/artifacts/expire_in_parser.rb new file mode 100644 index 00000000000..3e8a1fb86fc --- /dev/null +++ b/lib/gitlab/ci/build/artifacts/expire_in_parser.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + module Build + module Artifacts + class ExpireInParser + def self.validate_duration(value) + new(value).validate_duration + end + + def initialize(value) + @value = value + end + + def validate_duration + return true if never? + + parse + rescue ChronicDuration::DurationParseError + false + end + + def seconds_from_now + parse&.seconds&.from_now + end + + private + + attr_reader :value + + def parse + return if never? + + ChronicDuration.parse(value) + end + + def never? + value.to_s.casecmp('never') == 0 + end + end + end + end + end +end diff --git a/lib/gitlab/ci/config/entry/artifacts.rb b/lib/gitlab/ci/config/entry/artifacts.rb index a9a9636637f..206dbaea272 100644 --- a/lib/gitlab/ci/config/entry/artifacts.rb +++ b/lib/gitlab/ci/config/entry/artifacts.rb @@ -42,7 +42,7 @@ module Gitlab inclusion: { in: %w[on_success on_failure always], message: 'should be on_success, on_failure ' \ 'or always' } - validates :expire_in, duration: true + validates :expire_in, duration: { parser: ::Gitlab::Ci::Build::Artifacts::ExpireInParser } end end diff --git a/lib/gitlab/config/entry/legacy_validation_helpers.rb b/lib/gitlab/config/entry/legacy_validation_helpers.rb index ea5c887552e..415f6f77214 100644 --- a/lib/gitlab/config/entry/legacy_validation_helpers.rb +++ b/lib/gitlab/config/entry/legacy_validation_helpers.rb @@ -6,17 +6,27 @@ module Gitlab module LegacyValidationHelpers private - def validate_duration(value) - value.is_a?(String) && ChronicDuration.parse(value) + def validate_duration(value, parser = nil) + return false unless value.is_a?(String) + + if parser && parser.respond_to?(:validate_duration) + parser.validate_duration(value) + else + ChronicDuration.parse(value) + end rescue ChronicDuration::DurationParseError false end - def validate_duration_limit(value, limit) + def validate_duration_limit(value, limit, parser = nil) return false unless value.is_a?(String) - ChronicDuration.parse(value).second.from_now < - ChronicDuration.parse(limit).second.from_now + if parser && parser.respond_to?(:validate_duration_limit) + parser.validate_duration_limit(value, limit) + else + ChronicDuration.parse(value).second.from_now < + ChronicDuration.parse(limit).second.from_now + end rescue ChronicDuration::DurationParseError false end diff --git a/lib/gitlab/config/entry/validators.rb b/lib/gitlab/config/entry/validators.rb index 813ec9126f0..a7ec98ace6e 100644 --- a/lib/gitlab/config/entry/validators.rb +++ b/lib/gitlab/config/entry/validators.rb @@ -106,12 +106,12 @@ module Gitlab include LegacyValidationHelpers def validate_each(record, attribute, value) - unless validate_duration(value) + unless validate_duration(value, options[:parser]) record.errors.add(attribute, 'should be a duration') end if options[:limit] - unless validate_duration_limit(value, options[:limit]) + unless validate_duration_limit(value, options[:limit], options[:parser]) record.errors.add(attribute, 'should not exceed the limit') end end diff --git a/lib/gitlab/experimentation.rb b/lib/gitlab/experimentation.rb index 2dd06504542..87bc0238033 100644 --- a/lib/gitlab/experimentation.rb +++ b/lib/gitlab/experimentation.rb @@ -56,6 +56,9 @@ module Gitlab }, terms_opt_in: { tracking_category: 'Growth::Acquisition::Experiment::TermsOptIn' + }, + contact_sales_btn_in_app: { + tracking_category: 'Growth::Conversion::Experiment::ContactSalesInApp' } }.freeze diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b2b3c17d8e1..fc991854eb1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3824,6 +3824,9 @@ msgstr "" msgid "BillingPlans|per user" msgstr "" +msgid "BillingPlan|Contact sales" +msgstr "" + msgid "BillingPlan|Upgrade" msgstr "" @@ -21303,6 +21306,9 @@ msgstr "" msgid "SecurityConfiguration|Could not retrieve configuration data. Please refresh the page, or try again later." msgstr "" +msgid "SecurityConfiguration|Create Merge Request" +msgstr "" + msgid "SecurityConfiguration|Customize common SAST settings to suit your requirements. Configuration changes made here override those provided by GitLab and are excluded from updates. For details of more advanced configuration options, see the %{linkStart}GitLab SAST documentation%{linkEnd}." msgstr "" diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 21a0d01a9bf..4438831fb76 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -100,14 +100,11 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do context "when revocation fails" do it "displays an error message" do visit profile_personal_access_tokens_path - allow_any_instance_of(PersonalAccessToken).to receive(:update!).and_return(false) - - errors = ActiveModel::Errors.new(PersonalAccessToken.new).tap { |e| e.add(:name, "cannot be nil") } - allow_any_instance_of(PersonalAccessToken).to receive(:errors).and_return(errors) + allow_any_instance_of(PersonalAccessTokens::RevokeService).to receive(:revocation_permitted?).and_return(false) accept_confirm { click_on "Revoke" } expect(active_personal_access_tokens).to have_text(personal_access_token.name) - expect(page).to have_content("Could not revoke") + expect(page).to have_content("Not permitted to revoke") end end end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 08107b841d7..3538fe98628 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -168,6 +168,19 @@ RSpec.describe ApplicationHelper do it { expect(helper.active_when(false)).to eq(nil) } end + describe '#contact_sales_url' do + subject { helper.contact_sales_url } + + it 'passes a smoke test' do + is_expected.to eq('https://about.gitlab.com/sales') + end + + it 'changes if promo_url changes' do + allow(helper).to receive(:promo_url).and_return('https://somewhere.else') + is_expected.to eq('https://somewhere.else/sales') + end + end + describe '#support_url' do context 'when alternate support url is specified' do let(:alternate_url) { 'http://company.example.com/getting-help' } diff --git a/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb b/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb new file mode 100644 index 00000000000..0e26a9fa571 --- /dev/null +++ b/spec/lib/gitlab/ci/build/artifacts/expire_in_parser_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::Build::Artifacts::ExpireInParser do + describe '.validate_duration' do + subject { described_class.validate_duration(value) } + + context 'with never' do + let(:value) { 'never' } + + it { is_expected.to be_truthy } + end + + context 'with never value camelized' do + let(:value) { 'Never' } + + it { is_expected.to be_truthy } + end + + context 'with a duration' do + let(:value) { '1 Day' } + + it { is_expected.to be_truthy } + end + + context 'without a duration' do + let(:value) { 'something' } + + it { is_expected.to be_falsy } + end + end + + describe '#seconds_from_now' do + subject { described_class.new(value).seconds_from_now } + + context 'with never' do + let(:value) { 'never' } + + it { is_expected.to be_nil } + end + + context 'with an empty string' do + let(:value) { '' } + + it { is_expected.to be_nil } + end + + context 'with a duration' do + let(:value) { '1 day' } + + it { is_expected.to be_like_time(1.day.from_now) } + end + end +end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 3c5c0639d9c..80ec67e8cd5 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -1559,6 +1559,21 @@ module Gitlab }) end + it "returns artifacts with expire_in never keyword" do + config = YAML.dump({ + rspec: { + script: "rspec", + artifacts: { paths: ["releases/"], expire_in: "never" } + } + }) + + config_processor = Gitlab::Ci::YamlProcessor.new(config) + builds = config_processor.stage_builds_attributes("test") + + expect(builds.size).to eq(1) + expect(builds.first[:options][:artifacts][:expire_in]).to eq('never') + end + %w[on_success on_failure always].each do |when_state| it "returns artifacts for when #{when_state} defined" do config = YAML.dump({ diff --git a/spec/policies/personal_access_token_policy_spec.rb b/spec/policies/personal_access_token_policy_spec.rb index 2236af81763..706150597b2 100644 --- a/spec/policies/personal_access_token_policy_spec.rb +++ b/spec/policies/personal_access_token_policy_spec.rb @@ -14,7 +14,7 @@ RSpec.describe PersonalAccessTokenPolicy do end with_them do - context 'determine if a token is readable by a user' do + context 'determine if a token is readable or revocable by a user' do let(:user) { build_stubbed(user_type) } let(:token_owner) { owned_by_same_user ? user : build(:user) } let(:token) { build(:personal_access_token, user: token_owner) } @@ -26,6 +26,17 @@ RSpec.describe PersonalAccessTokenPolicy do end it { is_expected.to(expected_permitted? ? be_allowed(:read_token) : be_disallowed(:read_token)) } + it { is_expected.to(expected_permitted? ? be_allowed(:revoke_token) : be_disallowed(:revoke_token)) } end end + + context 'current_user is a blocked administrator', :enable_admin_mode do + subject { described_class.new(current_user, token) } + + let(:current_user) { create(:user, :admin, :blocked) } + let(:token) { create(:personal_access_token) } + + it { is_expected.to be_disallowed(:revoke_token) } + it { is_expected.to be_disallowed(:read_token) } + end end diff --git a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb index 9be69d4c562..e5c60bb539b 100644 --- a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb +++ b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb @@ -479,6 +479,16 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do expect(job.reload.artifacts_expire_at).to be_nil end end + + context 'when value is never' do + let(:expire_in) { 'never' } + let(:default_artifacts_expire_in) { '5 days' } + + it 'does not set expire_in' do + expect(response).to have_gitlab_http_status(:created) + expect(job.reload.artifacts_expire_at).to be_nil + end + end end end end diff --git a/spec/services/ci/create_job_artifacts_service_spec.rb b/spec/services/ci/create_job_artifacts_service_spec.rb index 3f5cf079025..72b0d220b11 100644 --- a/spec/services/ci/create_job_artifacts_service_spec.rb +++ b/spec/services/ci/create_job_artifacts_service_spec.rb @@ -73,7 +73,7 @@ RSpec.describe Ci::CreateJobArtifactsService do expect(metadata_artifact.expire_at).to be_within(1.minute).of(expected_expire_at) end - context 'when expire_in params is set' do + context 'when expire_in params is set to a specific value' do before do params.merge!('expire_in' => '2 hours') end @@ -89,6 +89,23 @@ RSpec.describe Ci::CreateJobArtifactsService do expect(metadata_artifact.expire_at).to be_within(1.minute).of(expected_expire_at) end end + + context 'when expire_in params is set to `never`' do + before do + params.merge!('expire_in' => 'never') + end + + it 'sets expiration date according to the parameter' do + expected_expire_at = nil + + expect(subject).to be_truthy + archive_artifact, metadata_artifact = job.job_artifacts.last(2) + + expect(job.artifacts_expire_at).to eq(expected_expire_at) + expect(archive_artifact.expire_at).to eq(expected_expire_at) + expect(metadata_artifact.expire_at).to eq(expected_expire_at) + end + end end end diff --git a/spec/services/personal_access_tokens/revoke_service_spec.rb b/spec/services/personal_access_tokens/revoke_service_spec.rb new file mode 100644 index 00000000000..5afa43cef76 --- /dev/null +++ b/spec/services/personal_access_tokens/revoke_service_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PersonalAccessTokens::RevokeService do + shared_examples_for 'a successfully revoked token' do + it { expect(subject.success?).to be true } + it { expect(service.token.revoked?).to be true } + end + + shared_examples_for 'an unsuccessfully revoked token' do + it { expect(subject.success?).to be false } + it { expect(service.token.revoked?).to be false } + end + + describe '#execute' do + subject { service.execute } + + let(:service) { described_class.new(current_user, token: token) } + + context 'when current_user is an administrator' do + let_it_be(:current_user) { create(:admin) } + let_it_be(:token) { create(:personal_access_token) } + + it_behaves_like 'a successfully revoked token' + end + + context 'when current_user is not an administrator' do + let_it_be(:current_user) { create(:user) } + + context 'token belongs to a different user' do + let_it_be(:token) { create(:personal_access_token) } + + it_behaves_like 'an unsuccessfully revoked token' + end + + context 'token belongs to current_user' do + let_it_be(:token) { create(:personal_access_token, user: current_user) } + + it_behaves_like 'a successfully revoked token' + end + end + end +end