Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЙрд▓реНрдпреВрд╢рдВрд╕ рдХреЗ S3 рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╡реЗрдмрд╣реБрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЗрд╡реЗрдВрдЯ-рд╕рдВрдЪрд╛рд▓рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг

Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЙрд▓реНрдпреВрд╢рдВрд╕ рдХреЗ S3 рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╡реЗрдмрд╣реБрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЗрд╡реЗрдВрдЯ-рд╕рдВрдЪрд╛рд▓рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг
рд░реБрдм рдЧреЛрд▓реНрдбрдмрд░реНрдЧ рдХреЙрдлреА рдорд╢реАрди

рдЗрд╡реЗрдВрдЯ-рд╕рдВрдЪрд╛рд▓рд┐рдд рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреА рд▓рд╛рдЧрдд рджрдХреНрд╖рддрд╛ рдХреЛ рдмрдврд╝рд╛рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ рдЙрд╕реА рд╕рдордп рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рдЙрдирдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЗрд╕реЗ рдХреИрд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдП рдФрд░ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдХреНрд▓рд╛рдЙрдб рдЗрдХрд╛рдЗрдпрд╛рдВ рди рдмрдирд╛рдИ рдЬрд╛рдПрдВ, рдЗрд╕ рдкрд░ рдХрдИ рд╡рд┐рдХрд▓реНрдк рд╣реИрдВред рдФрд░ рдЖрдЬ рдореИрдВ FaaS рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рд╡реЗрдмрд╣реБрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛ред рдореИрдВ рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рд╡реЗрдмрд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдШрдЯрдирд╛рдУрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХрд╛ рдПрдХ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдЙрджрд╛рд╣рд░рдг рджрд┐рдЦрд╛рдКрдВрдЧрд╛ред

рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдФрд░ рд╡реЗрдмрд╣реБрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рд╢рдмреНрджред рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдЖрдкрдХреЛ рдХрд┐рд╕реА рднреА рдбреЗрдЯрд╛ рдХреЛ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрд▓рд╛рдЙрдб рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ HTTP/HTTPS рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ S3 рдпрд╛ рдХрд┐рд╕реА рдЕрдиреНрдп рдПрдкреАрдЖрдИ (рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдЖрдзрд╛рд░ рдкрд░) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХреНрд╕реЗрд╕ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╡реЗрдмрд╣реБрдХ рдЖрдо рддреМрд░ рдкрд░ рдХрд╕реНрдЯрдо HTTP рдХреЙрд▓рдмреИрдХ рд╣реЛрддреЗ рд╣реИрдВред рд╡реЗ рдЖрдо рддреМрд░ рдкрд░ рдХрд┐рд╕реА рдШрдЯрдирд╛ рд╕реЗ рдЯреНрд░рд┐рдЧрд░ рд╣реЛрддреЗ рд╣реИрдВ, рдЬреИрд╕реЗ рдХреЛрдб рдХреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдзрдХреЗрд▓рд╛ рдЬрд╛рдирд╛ рдпрд╛ рдмреНрд▓реЙрдЧ рдкрд░ рдЯрд┐рдкреНрдкрдгреА рдкреЛрд╕реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ред рдЬрдм рдХреЛрдИ рдШрдЯрдирд╛ рдШрдЯрддреА рд╣реИ, рддреЛ рдореВрд▓ рд╕рд╛рдЗрдЯ рд╡реЗрдмрд╣реБрдХ рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдпреВрдЖрд░рдПрд▓ рдкрд░ рдПрдХ HTTP рдЕрдиреБрд░реЛрдз рднреЗрдЬрддреА рд╣реИред рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдЖрдк рдПрдХ рд╕рд╛рдЗрдЯ рдкрд░ рдИрд╡реЗрдВрдЯ рдмрдирд╛рдХрд░ рджреВрд╕рд░реА рд╕рд╛рдЗрдЯ рдкрд░ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдЯреНрд░рд┐рдЧрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рд╡рд┐рдХрд┐). рдРрд╕реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдЬрд╣рд╛рдВ рд╕реНрд░реЛрдд рд╕рд╛рдЗрдЯ рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ рднрдВрдбрд╛рд░рдг рд╣реИ, рдШрдЯрдирд╛рдПрдВ рдЗрд╕рдХреА рд╕рд╛рдордЧреНрд░реА рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рддреА рд╣реИрдВред

рдРрд╕реЗ рд╕рд░рд▓ рдорд╛рдорд▓реЛрдВ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдЬрдм рдРрд╕реЗ рд╕реНрд╡рдЪрд╛рд▓рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

  1. рдХрд┐рд╕реА рдЕрдиреНрдп рдХреНрд▓рд╛рдЙрдб рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╕рднреА рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдкреНрд░рддрд┐рдпрд╛рдВ рдмрдирд╛рдирд╛ред рдЬрдм рднреА рдлрд╝рд╛рдЗрд▓реЗрдВ рдЬреЛрдбрд╝реА рдЬрд╛рддреА рд╣реИрдВ рдпрд╛ рдмрджрд▓реА рдЬрд╛рддреА рд╣реИрдВ, рддреЛ рддреБрд░рдВрдд рдкреНрд░рддрд┐рд▓рд┐рдкрд┐рдпрд╛рдБ рдмрдирд╛рдИ рдЬрд╛рдиреА рдЪрд╛рд╣рд┐рдПред
  2. рдЧреНрд░рд╛рдлрд╝рд┐рдХ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рдердВрдмрдиреЗрд▓ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХрд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдирд┐рд░реНрдорд╛рдг, рддрд╕реНрд╡реАрд░реЛрдВ рдореЗрдВ рд╡реЙрдЯрд░рдорд╛рд░реНрдХ рдЬреЛрдбрд╝рдирд╛ рдФрд░ рдЕрдиреНрдп рдЫрд╡рд┐ рд╕рдВрд╢реЛрдзрдиред
  3. рдирдП рджрд╕реНрддрд╛рд╡реЗрдЬреЛрдВ рдХреЗ рдЖрдЧрдорди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рд╕реВрдЪрдирд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд┐рддрд░рд┐рдд рд▓реЗрдЦрд╛ рд╕реЗрд╡рд╛ рдХреНрд▓рд╛рдЙрдб рдкрд░ рд░рд┐рдкреЛрд░реНрдЯ рдЕрдкрд▓реЛрдб рдХрд░рддреА рд╣реИ, рдФрд░ рд╡рд┐рддреНрддреАрдп рдирд┐рдЧрд░рд╛рдиреА рдирдИ рд░рд┐рдкреЛрд░реНрдЯ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реВрдЪрдирд╛рдПрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреА рд╣реИ, рдЙрдирдХреА рдЬрд╛рдВрдЪ рдХрд░рддреА рд╣реИ рдФрд░ рдЙрдирдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рддреА рд╣реИ)ред
  4. рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХреБрдмреЗрд░рдиреЗрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдиреБрд░реЛрдз рдЙрддреНрдкрдиреНрди рдХрд░рдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЬреЛ рдЖрд╡рд╢реНрдпрдХ рдХрдВрдЯреЗрдирд░реЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдкреЙрдб рдмрдирд╛рддрд╛ рд╣реИ, рдЗрд╕рдореЗрдВ рдХрд╛рд░реНрдп рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рдмрд╛рдж рдХрдВрдЯреЗрдирд░ рдХреЛ рдврд╣рд╛ рджреЗрддрд╛ рд╣реИред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рддреМрд░ рдкрд░, рд╣рдо рдХрд╛рд░реНрдп 1 рдХрд╛ рдПрдХ рдкреНрд░рдХрд╛рд░ рдмрдирд╛рдПрдВрдЧреЗ, рдЬрдм Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЙрд▓реНрдпреВрд╢рдВрд╕ (MCS) рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдмрдХреЗрдЯ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рд╡реЗрдмрд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ AWS рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд▓реЛрдб рдХрд┐рдП рдЧрдП рдорд╛рдорд▓реЗ рдореЗрдВ, рд╡реЗрдмрд╣реБрдХ рдХреЛ рдПрдХ рдХрддрд╛рд░ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░рдХреЗ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛рд░реНрдп рдкреНрд░рджрд╛рди рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рд╣рдо рдЗрд╕рдХреЗ рдмрд┐рдирд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд░реЗрдВрдЧреЗред

рдХрд╛рд░реНрдп рдпреЛрдЬрдирд╛

рдЗрдВрдЯрд░реЗрдХреНрд╢рди рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдПрдорд╕реАрдПрд╕ рдкрд░ рдПрд╕3 рд╡реЗрдмрд╣реБрдХ рдХреЗ рд▓рд┐рдП рдЧрд╛рдЗрдб. рдХрд╛рд░реНрдп рдпреЛрдЬрдирд╛ рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддрддреНрд╡ рд╢рд╛рдорд┐рд▓ рд╣реИрдВ:

  • рдкреНрд░рдХрд╛рд╢рди рд╕реЗрд╡рд╛, рдЬреЛ S3 рд╕реНрдЯреЛрд░реЗрдЬ рд╕рд╛рдЗрдб рдкрд░ рд╣реИ рдФрд░ рд╡реЗрдмрдирд╣реБрдХ рдЯреНрд░рд┐рдЧрд░ рд╣реЛрдиреЗ рдкрд░ HTTP рдЕрдиреБрд░реЛрдз рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред
  • рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░, рдЬреЛ HTTP рдкреНрд░рдХрд╛рд╢рди рд╕реЗрд╡рд╛ рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕реБрдирддрд╛ рд╣реИ рдФрд░ рдЙрдЪрд┐рдд рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХрд░рддрд╛ рд╣реИред рд╕рд░реНрд╡рд░ рдХреЛ рдХрд┐рд╕реА рднреА рднрд╛рд╖рд╛ рдореЗрдВ рд▓рд┐рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ; рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╣рдо рд╕рд░реНрд╡рд░ рдХреЛ рдЧреЛ рдореЗрдВ рд▓рд┐рдЦреЗрдВрдЧреЗред

S3 рдПрдкреАрдЖрдИ рдореЗрдВ рд╡реЗрдмрд╣реБрдХ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╕реБрд╡рд┐рдзрд╛ рдкреНрд░рдХрд╛рд╢рди рд╕реЗрд╡рд╛ рдкрд░ рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕рд░реНрд╡рд░ рдХрд╛ рдкрдВрдЬреАрдХрд░рдг рд╣реИред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕рд░реНрд╡рд░ рдХреЛ рдкреНрд░рдХрд╛рд╢рди рд╕реЗрд╡рд╛ рд╕реЗ рд╕рдВрджреЗрд╢реЛрдВ рдХреА рд╕рджрд╕реНрдпрддрд╛ рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рдиреА рд╣реЛрдЧреА (рдЕрдиреНрдп рд╡реЗрдмрд╣реБрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ, рд╕рджрд╕реНрдпрддрд╛ рдХреА рдкреБрд╖реНрдЯрд┐ рдЖрдорддреМрд░ рдкрд░ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реЛрддреА рд╣реИ)ред

рддрджрдиреБрд╕рд╛рд░, рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╕рд░реНрд╡рд░ рдХреЛ рджреЛ рдореБрдЦреНрдп рдкрд░рд┐рдЪрд╛рд▓рдиреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП:

  • рдкрдВрдЬреАрдХрд░рдг рдХреА рдкреБрд╖реНрдЯрд┐ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХрд╛рд╢рди рд╕реЗрд╡рд╛ рдХреЗ рдЕрдиреБрд░реЛрдз рдХрд╛ рдЬрд╡рд╛рдм рджреЗрдВ,
  • рдЖрдиреЗ рд╡рд╛рд▓реА рдШрдЯрдирд╛рдУрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдВред

рдПрдХ рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛

рд╡реЗрдмрд╣реБрдХ рд░рд┐рд╕реАрд╡рд┐рдВрдЧ рд╕рд░реНрд╡рд░ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рд▓рд┐рдирдХреНрд╕ рд╕рд░реНрд╡рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕ рдЖрд▓реЗрдЦ рдореЗрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рддреМрд░ рдкрд░, рд╣рдо рдПрдХ рд╡рд░реНрдЪреБрдЕрд▓ рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕реЗ рд╣рдо рдПрдорд╕реАрдПрд╕ рдкрд░ рддреИрдирд╛рдд рдХрд░рддреЗ рд╣реИрдВред

рдЖрдЗрдП рдЖрд╡рд╢реНрдпрдХ рд╕реЙрдлрд╝реНрдЯрд╡реЗрдпрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ рдФрд░ рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВред

ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install git
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  bc dns-root-data dnsmasq-base ebtables landscape-common liblxc-common 
liblxc1 libuv1 lxcfs lxd lxd-client python3-attr python3-automat 
python3-click python3-constantly python3-hyperlink
  python3-incremental python3-pam python3-pyasn1-modules 
python3-service-identity python3-twisted python3-twisted-bin 
python3-zope.interface uidmap xdelta3
Use 'sudo apt autoremove' to remove them.
Suggested packages:
  git-daemon-run | git-daemon-sysvinit git-doc git-el git-email git-gui 
gitk gitweb git-cvs git-mediawiki git-svn
The following NEW packages will be installed:
  git
0 upgraded, 1 newly installed, 0 to remove and 46 not upgraded.
Need to get 3915 kB of archives.
After this operation, 32.3 MB of additional disk space will be used.
Get:1 http://MS1.clouds.archive.ubuntu.com/ubuntu bionic-updates/main 
amd64 git amd64 1:2.17.1-1ubuntu0.7 [3915 kB]
Fetched 3915 kB in 1s (5639 kB/s)
Selecting previously unselected package git.
(Reading database ... 53932 files and directories currently installed.)
Preparing to unpack .../git_1%3a2.17.1-1ubuntu0.7_amd64.deb ...
Unpacking git (1:2.17.1-1ubuntu0.7) ...
Setting up git (1:2.17.1-1ubuntu0.7) ...

рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рдХреЗ рд╕рд╛рде рдлрд╝реЛрд▓реНрдбрд░ рдХреЛ рдХреНрд▓реЛрди рдХрд░реЗрдВ:

ubuntu@ubuntu-basic-1-2-10gb:~$ git clone
https://github.com/RomanenkoDenys/s3-webhook.git
Cloning into 's3-webhook'...
remote: Enumerating objects: 48, done.
remote: Counting objects: 100% (48/48), done.
remote: Compressing objects: 100% (27/27), done.
remote: Total 114 (delta 20), reused 45 (delta 18), pack-reused 66
Receiving objects: 100% (114/114), 23.77 MiB | 20.25 MiB/s, done.
Resolving deltas: 100% (49/49), done.

рдЖрдЗрдП рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░реЗрдВ:

ubuntu@ubuntu-basic-1-2-10gb:~$ cd s3-webhook/
ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80

рдкреНрд░рдХрд╛рд╢рди рд╕реЗрд╡рд╛ рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдВ

рдЖрдк рдЕрдкрдиреЗ рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рдХреЛ рдПрдкреАрдЖрдИ рдпрд╛ рд╡реЗрдм рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкрдВрдЬреАрдХреГрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рд░рд▓рддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡реЗрдм рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкрдВрдЬреАрдХрд░рдг рдХрд░реЗрдВрдЧреЗ:

  1. рдЪрд▓рд┐рдП рдмрд╛рд▓реНрдЯреА рдЕрдиреБрднрд╛рдЧ рдкрд░ рдЪрд▓рддреЗ рд╣реИрдВ рдирд┐рдпрдВрддреНрд░рдг рдХрдХреНрд╖ рдореЗрдВ.
  2. рдЙрд╕ рдмрдХреЗрдЯ рдкрд░ рдЬрд╛рдПрдБ рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд╡реЗрдмрд╣реБрдХ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЧрд┐рдпрд░ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ:

Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЙрд▓реНрдпреВрд╢рдВрд╕ рдХреЗ S3 рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╡реЗрдмрд╣реБрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЗрд╡реЗрдВрдЯ-рд╕рдВрдЪрд╛рд▓рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг

рд╡реЗрдмрд╣реБрдХ рдЯреИрдм рдкрд░ рдЬрд╛рдПрдВ рдФрд░ рдЬреЛрдбрд╝реЗрдВ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ:

Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЙрд▓реНрдпреВрд╢рдВрд╕ рдХреЗ S3 рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╡реЗрдмрд╣реБрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЗрд╡реЗрдВрдЯ-рд╕рдВрдЪрд╛рд▓рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг
рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рднрд░реЗрдВ:

Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЙрд▓реНрдпреВрд╢рдВрд╕ рдХреЗ S3 рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╡реЗрдмрд╣реБрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЗрд╡реЗрдВрдЯ-рд╕рдВрдЪрд╛рд▓рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг

рдЖрдИрдбреА - рд╡реЗрдмрд╣реБрдХ рдХрд╛ рдирд╛рдо.

рдШрдЯрдирд╛ - рдХреМрди рд╕реА рдШрдЯрдирд╛рдПрдБ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░рдиреА рд╣реИрдВред рд╣рдордиреЗ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ (рдЬреЛрдбрд╝рдиреЗ рдФрд░ рд╣рдЯрд╛рдиреЗ) рдХреЗ рджреМрд░рд╛рди рд╣реЛрдиреЗ рд╡рд╛рд▓реА рд╕рднреА рдШрдЯрдирд╛рдУрдВ рдХрд╛ рдкреНрд░рд╕рд╛рд░рдг рд╕реЗрдЯ рдХрд░ рджрд┐рдпрд╛ рд╣реИред

рдпреВрдЖрд░рдПрд▓ - рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╕рд░реНрд╡рд░ рдкрддрд╛ред

рдлрд╝рд┐рд▓реНрдЯрд░ рдЙрдкрд╕рд░реНрдЧ/рдкреНрд░рддреНрдпрдп рдПрдХ рдлрд╝рд┐рд▓реНрдЯрд░ рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдЙрди рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд▓рд┐рдП рд╡реЗрдмрд╣реБрдХ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдЬрд┐рдирдХреЗ рдирд╛рдо рдХреБрдЫ рдирд┐рдпрдореЛрдВ рд╕реЗ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╡реЗрдмрд╣реБрдХ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ .png рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╡рд╛рд▓реА рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдЯреНрд░рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рд┐рд▓реНрдЯрд░ рдкреНрд░рддреНрдпрдп рдЖрдкрдХреЛ "рдкреАрдПрдирдЬреА" рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ред

рд╡рд░реНрддрдорд╛рди рдореЗрдВ, рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдкреЛрд░реНрдЯ 80 рдФрд░ 443 рд╕рдорд░реНрдерд┐рдд рд╣реИрдВред

рдЖрдЗрдП рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ рд╣реБрдХ рдЬреЛрдбрд╝реЗрдВ рдФрд░ рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рджреЗрдЦреЗрдВрдЧреЗ:

Mail.ru рдХреНрд▓рд╛рдЙрдб рд╕реЙрд▓реНрдпреВрд╢рдВрд╕ рдХреЗ S3 рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдЯреЛрд░реЗрдЬ рдореЗрдВ рд╡реЗрдмрд╣реБрдХ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдЗрд╡реЗрдВрдЯ-рд╕рдВрдЪрд╛рд▓рд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг
рд╣реБрдХ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛.

рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╕рд░реНрд╡рд░ рдЕрдкрдиреЗ рд▓реЙрдЧ рдореЗрдВ рд╣реБрдХ рдкрдВрдЬреАрдХрд░рдг рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреА рдкреНрд░рдЧрддрд┐ рджрд┐рдЦрд╛рддрд╛ рд╣реИ:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80
2020/06/15 12:01:14 [POST] incoming HTTP request from 
95.163.216.92:42530
2020/06/15 12:01:14 Got timestamp: 2020-06-15T15:01:13+03:00 TopicArn: 
mcs5259999770|myfiles-ash|s3:ObjectCreated:*,s3:ObjectRemoved:* Token: 
E2itMqAMUVVZc51pUhFWSp13DoxezvRxkUh5P7LEuk1dEe9y URL: 
http://89.208.199.220/webhook
2020/06/15 12:01:14 Generate responce signature: 
3754ce36636f80dfd606c5254d64ecb2fd8d555c27962b70b4f759f32c76b66d

рдкрдВрдЬреАрдХрд░рдг рдкреВрд░рд╛ рд╣реЛ рдЧрдпрд╛ рд╣реИ. рдЕрдЧрд▓реЗ рднрд╛рдЧ рдореЗрдВ, рд╣рдо рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдкрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рджреЗрдЦреЗрдВрдЧреЗред

рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рд░реНрд╡рд░ рдХрд╛ рд╡рд┐рд╡рд░рдг

рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рд╕рд░реНрд╡рд░ рдХреЛ рдЧреЛ рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред рдЖрдЗрдП рдЗрд╕рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдкрд░ рдирдЬрд░ рдбрд╛рд▓реЗрдВред

package main

// Generate hmac_sha256_hex
func HmacSha256hex(message string, secret string) string {
}

// Generate hmac_sha256
func HmacSha256(message string, secret string) string {
}

// Send subscription confirmation
func SubscriptionConfirmation(w http.ResponseWriter, req *http.Request, body []byte) {
}

// Send subscription confirmation
func GotRecords(w http.ResponseWriter, req *http.Request, body []byte) {
}

// Liveness probe
func Ping(w http.ResponseWriter, req *http.Request) {
    // log request
    log.Printf("[%s] incoming HTTP Ping request from %sn", req.Method, req.RemoteAddr)
    fmt.Fprintf(w, "Pongn")
}

//Webhook
func Webhook(w http.ResponseWriter, req *http.Request) {
}

func main() {

    // get command line args
    bindPort := flag.Int("port", 80, "number between 1-65535")
    bindAddr := flag.String("address", "", "ip address in dot format")
    flag.StringVar(&actionScript, "script", "", "external script to execute")
    flag.Parse()

    http.HandleFunc("/ping", Ping)
    http.HandleFunc("/webhook", Webhook)

log.Fatal(http.ListenAndServe(*bindAddr+":"+strconv.Itoa(*bindPort), nil))
}

рдореБрдЦреНрдп рдХрд╛рд░реНрдпреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:

  • рдкрд┐рдВрдЧ() - рдПрдХ рдорд╛рд░реНрдЧ рдЬреЛ рдпреВрдЖрд░рдПрд▓/рдкрд┐рдВрдЧ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИ, рдЬреАрд╡рдВрддрддрд╛ рдЬрд╛рдВрдЪ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдиред
  • рд╡реЗрдмрд╣реБрдХ() - рдореБрдЦреНрдп рдорд╛рд░реНрдЧ, рдпреВрдЖрд░рдПрд▓/рд╡реЗрдмрд╣реБрдХ рд╣реИрдВрдбрд▓рд░:
    • рдкреНрд░рдХрд╛рд╢рди рд╕реЗрд╡рд╛ рдкрд░ рдкрдВрдЬреАрдХрд░рдг рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рддрд╛ рд╣реИ (рд╕рджрд╕реНрдпрддрд╛ рдкреБрд╖реНрдЯрд┐рдХрд░рдг рдлрд╝рдВрдХреНрд╢рди рдкрд░ рдЬрд╛рдПрдВ),
    • рдЖрдиреЗ рд╡рд╛рд▓реЗ рд╡реЗрдмрд╣реБрдХ (рдЧреЛрд░реЗрдХреЙрд░реНрдбреНрд╕ рдлрд╝рдВрдХреНрд╢рди) рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИред
  • рдлрд╝рдВрдХреНрд╢рди HmacSha256 рдФрд░ HmacSha256hex рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХреА рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП рд╣реЗрдХреНрд╕рд╛рдбреЗрд╕рд┐рдорд▓ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреА рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд░реВрдк рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдХреЗ рд╕рд╛рде HMAC-SHA256 рдФрд░ HMAC-SHA256 рдПрдиреНрдХреНрд░рд┐рдкреНрд╢рди рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИрдВред
  • рдореБрдЦреНрдп рдореБрдЦреНрдп рдХрд╛рд░реНрдп рд╣реИ, рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдпреВрдЖрд░рдПрд▓ рд╣реИрдВрдбрд▓рд░ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рддрд╛ рд╣реИред

рд╕рд░реНрд╡рд░ рджреНрд╡рд╛рд░рд╛ рд╕реНрд╡реАрдХреГрдд рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдкреИрд░рд╛рдореАрдЯрд░:

  • -рдкреЛрд░реНрдЯ рд╡рд╣ рдкреЛрд░реНрдЯ рд╣реИ рдЬрд┐рд╕ рдкрд░ рд╕рд░реНрд╡рд░ рд╕реБрдиреЗрдЧрд╛ред
  • -рдкрддрд╛ - рдЖрдИрдкреА рдкрддрд╛ рдЬрд┐рд╕реЗ рд╕рд░реНрд╡рд░ рд╕реБрдиреЗрдЧрд╛ред
  • -рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдПрдХ рдмрд╛рд╣рд░реА рдкреНрд░реЛрдЧреНрд░рд╛рдо рд╣реИ рдЬрд┐рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдЖрдиреЗ рд╡рд╛рд▓реЗ рд╣реБрдХ рдХреЗ рд▓рд┐рдП рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдЖрдЗрдП рдХреБрдЫ рдХрд╛рд░реНрдпреЛрдВ рдкрд░ рдХрд░реАрдм рд╕реЗ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:

//Webhook
func Webhook(w http.ResponseWriter, req *http.Request) {

    // Read body
    body, err := ioutil.ReadAll(req.Body)
    defer req.Body.Close()
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    // log request
    log.Printf("[%s] incoming HTTP request from %sn", req.Method, req.RemoteAddr)
    // check if we got subscription confirmation request
    if strings.Contains(string(body), 
""Type":"SubscriptionConfirmation"") {
        SubscriptionConfirmation(w, req, body)
    } else {
        GotRecords(w, req, body)
    }

}

рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдкрдВрдЬреАрдХрд░рдг рдпрд╛ рд╡реЗрдмрд╣реБрдХ рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рдиреЗ рдХрд╛ рдЕрдиреБрд░реЛрдз рдЖрдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╕реЗ рдкреНрд░рд▓реЗрдЦрди, рдпрджрд┐ рдкрдВрдЬреАрдХрд░рдг рдХреА рдкреБрд╖реНрдЯрд┐ рд╣реЛ рдЬрд╛рддреА рд╣реИ, рддреЛ рдкреЛрд╕реНрдЯ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд JSON рд╕рдВрд░рдЪрдирд╛ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреА рд╣реИ:

POST http://test.com HTTP/1.1
x-amz-sns-messages-type: SubscriptionConfirmation
content-type: application/json

{
    "Timestamp":"2019-12-26T19:29:12+03:00",
    "Type":"SubscriptionConfirmation",
    "Message":"You have chosen to subscribe to the topic $topic. To confirm the subscription you need to response with calculated signature",
    "TopicArn":"mcs2883541269|bucketA|s3:ObjectCreated:Put",
    "SignatureVersion":1,
    "Token":┬лRPE5UuG94rGgBH6kHXN9FUPugFxj1hs2aUQc99btJp3E49tA┬╗
}

рдЗрд╕ рдкреНрд░рд╢реНрди рдХрд╛ рдЙрддреНрддрд░ рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ:

content-type: application/json

{"signature":┬лea3fce4bb15c6de4fec365d36bcebbc34ccddf54616d5ca12e1972f82b6d37af┬╗}

рдЬрд╣рд╛рдВ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХреА рдЧрдгрдирд╛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХреА рдЬрд╛рддреА рд╣реИ:

signature = hmac_sha256(url, hmac_sha256(TopicArn, 
hmac_sha256(Timestamp, Token)))

рдпрджрд┐ рдХреЛрдИ рд╡реЗрдмрд╣реБрдХ рдЖрддрд╛ рд╣реИ, рддреЛ рдкреЛрд╕реНрдЯ рдЕрдиреБрд░реЛрдз рдХреА рд╕рдВрд░рдЪрдирд╛ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддреА рд╣реИ:

POST <url> HTTP/1.1
x-amz-sns-messages-type: SubscriptionConfirmation

{ "Records":
    [
        {
            "s3": {
                "object": {
                    "eTag":"aed563ecafb4bcc5654c597a421547b2",
                    "sequencer":1577453615,
                    "key":"some-file-to-bucket",
                    "size":100
                },
            "configurationId":"1",
            "bucket": {
                "name": "bucketA",
                "ownerIdentity": {
                    "principalId":"mcs2883541269"}
                },
                "s3SchemaVersion":"1.0"
            },
            "eventVersion":"1.0",
            "requestParameters":{
                "sourceIPAddress":"185.6.245.156"
            },
            "userIdentity": {
                "principalId":"2407013e-cbc1-415f-9102-16fb9bd6946b"
            },
            "eventName":"s3:ObjectCreated:Put",
            "awsRegion":"ru-msk",
            "eventSource":"aws:s3",
            "responseElements": {
                "x-amz-request-id":"VGJR5rtJ"
            }
        }
    ]
}

рддрджрдиреБрд╕рд╛рд░, рдЕрдиреБрд░реЛрдз рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдЖрдкрдХреЛ рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рдХреЛ рдХреИрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПред рдореИрдВрдиреЗ рд╕рдВрдХреЗрддрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреЛ рдЪреБрдирд╛ "Type":"SubscriptionConfirmation", рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╕рджрд╕реНрдпрддрд╛ рдкреБрд╖реНрдЯрд┐рдХрд░рдг рдЕрдиреБрд░реЛрдз рдореЗрдВ рдореМрдЬреВрдж рд╣реИ рдФрд░ рд╡реЗрдмрд╣реБрдХ рдореЗрдВ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИред POST рдЕрдиреБрд░реЛрдз рдореЗрдВ рдЗрд╕ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐/рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХрд╛ рдЖрдЧреЗ рдирд┐рд╖реНрдкрд╛рджрди рдпрд╛ рддреЛ рдлрд╝рдВрдХреНрд╢рди рдкрд░ рдЬрд╛рддрд╛ рд╣реИ SubscriptionConfirmation, рдпрд╛ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ GotRecords.

рд╣рдо рд╕рджрд╕реНрдпрддрд╛ рдкреБрд╖реНрдЯрд┐рдХрд░рдг рдлрд╝рдВрдХреНрд╢рди рдкрд░ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ; рдЗрд╕реЗ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдкреНрд░рд▓реЗрдЦрди. рдЖрдк рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рд╕реНрд░реЛрдд рдХреЛрдб рдпрд╣рд╛рдВ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдЧрд┐рдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА.

GotRecords рдлрд╝рдВрдХреНрд╢рди рдЖрдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреБрд░реЛрдз рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд░рд┐рдХреЙрд░реНрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде рдПрдХ рдмрд╛рд╣рд░реА рд╕реНрдХреНрд░рд┐рдкреНрдЯ (рдЬрд┐рд╕рдХрд╛ рдирд╛рдо -рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкреИрд░рд╛рдореАрдЯрд░ рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛) рдХреЛ рдХреЙрд▓ рдХрд░рддрд╛ рд╣реИ:

  • рдмрд╛рд▓реНрдЯреА рдХрд╛ рдирд╛рдо
  • рд╡рд╕реНрддреБ рдХреБрдВрдЬреА
  • рдХрд╛рд░реНрдп:
    • рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ - рдпрджрд┐ рдореВрд▓ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдЗрд╡реЗрдВрдЯрдирд╛рдо = рдСрдмреНрдЬреЗрдХреНрдЯрдХреНрд░рд┐рдПрдЯреЗрдб | рдкреБрдЯрдСрдмреНрдЬреЗрдХреНрдЯ | рдкреБрдЯрдСрдмреНрдЬреЗрдХреНрдЯрдХреЙрдкреА
    • рд╣рдЯрд╛рдПрдВ - рдпрджрд┐ рдореВрд▓ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдЗрд╡реЗрдВрдЯрдирд╛рдо = рдСрдмреНрдЬреЗрдХреНрдЯ рд░рд┐рдореВрд╡реНрдб | рдСрдмреНрдЬреЗрдХреНрдЯ рд╣рдЯрд╛рдПрдБ

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдпрджрд┐ рдХреЛрдИ рд╣реБрдХ рдкреЛрд╕реНрдЯ рдЕрдиреБрд░реЛрдз рдХреЗ рд╕рд╛рде рдЖрддрд╛ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рд╡рд░реНрдгрд┐рдд рд╣реИ рдКрдкрд░, рдФрд░ рдкреИрд░рд╛рдореАрдЯрд░ -script=script.sh рддреЛ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛:

script.sh  bucketA some-file-to-bucket copy

рдпрд╣ рд╕рдордЭрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдпрд╣ рд╡реЗрдмрд╣реБрдХ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╕рд░реНрд╡рд░ рдкреВрд░реНрдг рдЙрддреНрдкрд╛рджрди рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИ, рдмрд▓реНрдХрд┐ рд╕рдВрднрд╛рд╡рд┐рдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдПрдХ рд╕рд░рд▓реАрдХреГрдд рдЙрджрд╛рд╣рд░рдг рд╣реИред

рдХрд╛рд░реНрдп рдХрд╛ рдЙрджрд╛рд╣рд░рдг

рдЖрдЗрдП MCS рдореЗрдВ рдореБрдЦреНрдп рдмрдХреЗрдЯ рд╕реЗ AWS рдореЗрдВ рдмреИрдХрдЕрдк рдмрдХреЗрдЯ рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░реЗрдВред рдореБрдЦреНрдп рдмрдХреЗрдЯ рдХреЛ myfiles-ash рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдмреИрдХрдЕрдк рдХреЛ myfiles-backup рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ (AWS рдореЗрдВ рдмрдХреЗрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЗрд╕ рдЖрд▓реЗрдЦ рдХреЗ рджрд╛рдпрд░реЗ рд╕реЗ рдкрд░реЗ рд╣реИ)ред рддрджрдиреБрд╕рд╛рд░, рдЬрдм рдХрд┐рд╕реА рдлрд╝рд╛рдЗрд▓ рдХреЛ рдореБрдЦреНрдп рдмрдХреЗрдЯ рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЙрд╕рдХреА рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдмреИрдХрдЕрдк рдмрдХреЗрдЯ рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрдиреА рдЪрд╛рд╣рд┐рдП, рдФрд░ рдЬрдм рдЙрд╕реЗ рдореБрдЦреНрдп рдмрдХреЗрдЯ рд╕реЗ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЙрд╕реЗ рдмреИрдХрдЕрдк рдмрдХреЗрдЯ рдореЗрдВ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╣рдо awscli рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмрдХреЗрдЯ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░реЗрдВрдЧреЗ, рдЬреЛ MCS рдХреНрд▓рд╛рдЙрдб рд╕реНрдЯреЛрд░реЗрдЬ рдФрд░ AWS рдХреНрд▓рд╛рдЙрдб рд╕реНрдЯреЛрд░реЗрдЬ рджреЛрдиреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдВрдЧрдд рд╣реИред

ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install awscli
Reading package lists... Done
Building dependency tree
Reading state information... Done
After this operation, 34.4 MB of additional disk space will be used.
Unpacking awscli (1.14.44-1ubuntu1) ...
Setting up awscli (1.14.44-1ubuntu1) ...

рдЖрдЗрдП S3 MCS API рддрдХ рдкрд╣реБрдВрдЪ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile mcs
AWS Access Key ID [None]: hdywEPtuuJTExxxxxxxxxxxxxx
AWS Secret Access Key [None]: hDz3SgxKwXoxxxxxxxxxxxxxxxxxx
Default region name [None]:
Default output format [None]:

рдЖрдЗрдП AWS S3 API рддрдХ рдкрд╣реБрдВрдЪ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile aws
AWS Access Key ID [None]: AKIAJXXXXXXXXXXXX
AWS Secret Access Key [None]: dfuerphOLQwu0CreP5Z8l5fuXXXXXXXXXXXXXXXX
Default region name [None]:
Default output format [None]:

рдЖрдЗрдП рдПрдХреНрд╕реЗрд╕ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:

рдПрдбрдмреНрд▓реНрдпреВрдПрд╕ рдХреЗ рд▓рд┐рдП:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile aws
2020-07-06 08:44:11 myfiles-backup

рдПрдорд╕реАрдПрд╕ рдХреЗ рд▓рд┐рдП, рдХрдорд╛рдВрдб рдЪрд▓рд╛рддреЗ рд╕рдордп рдЖрдкрдХреЛ -рдПрдВрдбрдкреЙрдЗрдВрдЯ-рдпреВрдЖрд░рдПрд▓ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛:

ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile mcs --endpoint-url 
https://hb.bizmrg.com
2020-02-04 06:38:05 databasebackups-0cdaaa6402d4424e9676c75a720afa85
2020-05-27 10:08:33 myfiles-ash

рдкрд╣реБрдБрдЪ рдЧрдпрд╛.

рдЕрдм рдЖрдиреЗ рд╡рд╛рд▓реЗ рд╣реБрдХ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд▓рд┐рдЦреЗрдВ, рдЖрдЗрдП рдЗрд╕реЗ s3_backup_mcs_aws.sh рдХрд╣рддреЗ рд╣реИрдВ

#!/bin/bash
# Require aws cli
# if file added тАФ copy it to backup bucket
# if file removed тАФ remove it from backup bucket
# Variables
ENDPOINT_MCS="https://hb.bizmrg.com"
AWSCLI_MCS=`which aws`" --endpoint-url ${ENDPOINT_MCS} --profile mcs s3"
AWSCLI_AWS=`which aws`" --profile aws s3"
BACKUP_BUCKET="myfiles-backup"

SOURCE_BUCKET=""
SOURCE_FILE=""
ACTION=""

SOURCE="s3://${SOURCE_BUCKET}/${SOURCE_FILE}"
TARGET="s3://${BACKUP_BUCKET}/${SOURCE_FILE}"
TEMP="/tmp/${SOURCE_BUCKET}/${SOURCE_FILE}"

case ${ACTION} in
    "copy")
    ${AWSCLI_MCS} cp "${SOURCE}" "${TEMP}"
    ${AWSCLI_AWS} cp "${TEMP}" "${TARGET}"
    rm ${TEMP}
    ;;

    "delete")
    ${AWSCLI_AWS} rm ${TARGET}
    ;;

    *)
    echo "Usage: 
#!/bin/bash
# Require aws cli
# if file added тАФ copy it to backup bucket
# if file removed тАФ remove it from backup bucket
# Variables
ENDPOINT_MCS="https://hb.bizmrg.com"
AWSCLI_MCS=`which aws`" --endpoint-url ${ENDPOINT_MCS} --profile mcs s3"
AWSCLI_AWS=`which aws`" --profile aws s3"
BACKUP_BUCKET="myfiles-backup"
SOURCE_BUCKET="${1}"
SOURCE_FILE="${2}"
ACTION="${3}"
SOURCE="s3://${SOURCE_BUCKET}/${SOURCE_FILE}"
TARGET="s3://${BACKUP_BUCKET}/${SOURCE_FILE}"
TEMP="/tmp/${SOURCE_BUCKET}/${SOURCE_FILE}"
case ${ACTION} in
"copy")
${AWSCLI_MCS} cp "${SOURCE}" "${TEMP}"
${AWSCLI_AWS} cp "${TEMP}" "${TARGET}"
rm ${TEMP}
;;
"delete")
${AWSCLI_AWS} rm ${TARGET}
;;
*)
echo "Usage: ${0} sourcebucket sourcefile copy/delete"
exit 1
;;
esac
sourcebucket sourcefile copy/delete" exit 1 ;; esac

рдЖрдЗрдП рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░реЗрдВ:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ sudo ./s3-webhook -port 80 -
script scripts/s3_backup_mcs_aws.sh

рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдорд╕реАрдПрд╕ рд╡реЗрдм рдЗрдВрдЯрд░рдлрд╝реЗрд╕ test.txt рдлрд╝рд╛рдЗрд▓ рдХреЛ myfiles-ash рдмрдХреЗрдЯ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред рдХрдВрд╕реЛрд▓ рд▓реЙрдЧ рджрд┐рдЦрд╛рддреЗ рд╣реИрдВ рдХрд┐ рд╡реЗрдмрд╣реБрдХ рд╕рд░реНрд╡рд░ рд╕реЗ рдПрдХ рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛:

2020/07/06 09:43:08 [POST] incoming HTTP request from 
95.163.216.92:56612
download: s3://myfiles-ash/test.txt to ../../../tmp/myfiles-ash/test.txt
upload: ../../../tmp/myfiles-ash/test.txt to 
s3://myfiles-backup/test.txt

рдЖрдЗрдП AWS рдореЗрдВ myfiles-рдмреИрдХрдЕрдк рдмрдХреЗрдЯ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls 
myfiles-backup
2020-07-06 09:43:10       1104 test.txt

рдЕрдм, рд╡реЗрдм рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рд╣рдо рдлрд╝рд╛рдЗрд▓ рдХреЛ myfiles-ash рдмрдХреЗрдЯ рд╕реЗ рд╣рдЯрд╛ рджреЗрдВрдЧреЗред

рд╕рд░реНрд╡рд░ рд▓реЙрдЧ:

2020/07/06 09:44:46 [POST] incoming HTTP request from 
95.163.216.92:58224
delete: s3://myfiles-backup/test.txt

рдмрд╛рд▓реНрдЯреА рд╕рд╛рдордЧреНрд░реА:

ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls 
myfiles-backup
ubuntu@ubuntu-basic-1-2-10gb:~$

рдлрд╝рд╛рдЗрд▓ рд╣рдЯрд╛ рджреА рдЧрдИ рд╣реИ, рд╕рдорд╕реНрдпрд╛ рд╣рд▓ рд╣реЛ рдЧрдИ рд╣реИ.

рдирд┐рд╖реНрдХрд░реНрд╖ рдФрд░ рдХрд╛рд░реНрдп

рдЗрд╕ рдЖрд▓реЗрдЦ рдореЗрдВ рдкреНрд░рдпреБрдХреНрдд рд╕рднреА рдХреЛрдб рд╣реИрдВ рдореЗрд░реЗ рднрдВрдбрд╛рд░ рдореЗрдВ. рд╡реЗрдмрд╣реБрдХ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдФрд░ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдЧрд┐рдирдиреЗ рдХреЗ рдЙрджрд╛рд╣рд░рдг рднреА рд╣реИрдВред

рдпрд╣ рдХреЛрдб рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдЕрдзрд┐рдХ рдХреБрдЫ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдЖрдк рдЕрдкрдиреА рдЧрддрд┐рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ S3 рд╡реЗрдмрд╣реБрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рд╢реБрд░реБрдЖрдд рдореЗрдВ рдХрд╣рд╛ рдерд╛, рдпрджрд┐ рдЖрдк рдЙрддреНрдкрд╛рджрди рдореЗрдВ рдРрд╕реЗ рд╕рд░реНрд╡рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдХрдо рд╕реЗ рдХрдо рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рд╕рд░реНрд╡рд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛: рдЖрдиреЗ рд╡рд╛рд▓реЗ рд╡реЗрдмрд╣реБрдХ рдХреЛ рдПрдХ рдХрддрд╛рд░ (RabbitMQ рдпрд╛ NATS) рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ, рдФрд░ рд╡рд╣рд╛рдВ рд╕реЗ рдЙрдиреНрд╣реЗрдВ рдкрд╛рд░реНрд╕ рдХрд░реЗрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдВ рдХрд╛рд░реНрдпрдХрд░реНрддрд╛ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд╕рд╛рде. рдЕрдиреНрдпрдерд╛, рдЬрдм рд╡реЗрдмрд╣реБрдХ рдмрдбрд╝реЗ рдкреИрдорд╛рдиреЗ рдкрд░ рдЖрддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд░реНрд╡рд░ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреА рдХрдореА рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝ рд╕рдХрддрд╛ рд╣реИред рдХрддрд╛рд░реЛрдВ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдЖрдкрдХреЛ рд╕рд░реНрд╡рд░ рдФрд░ рд╢реНрд░рдорд┐рдХреЛрдВ рдХреЛ рд╡рд┐рддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд╕рд╛рде-рд╕рд╛рде рд╡рд┐рдлрд▓рддрд╛рдУрдВ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рджреЛрд╣рд░рд╛рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рд▓реЙрдЧрд┐рдВрдЧ рдХреЛ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддреГрдд рдФрд░ рдЕрдзрд┐рдХ рдорд╛рдирдХреАрдХреГрдд рдореЗрдВ рдмрджрд▓рдиреЗ рдХреА рднреА рд╕рд▓рд╛рд╣ рджреА рдЬрд╛рддреА рд╣реИред

рд╕реМрднрд╛рдЧреНрдп!

рд╡рд┐рд╖рдп рдкрд░ рдЕрдзрд┐рдХ рдкрдврд╝рдирд╛:

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ