@@ -613,19 +613,6 @@ defmodule NervesHub.Devices do
613613 @ type source_firmware_id ( ) :: firmware_id ( )
614614 @ type target_firmware_id ( ) :: firmware_id ( )
615615
616- @ spec get_device_firmware_for_delta_generation_by_product ( binary ( ) ) ::
617- list ( { source_firmware_id ( ) , target_firmware_id ( ) } )
618- def get_device_firmware_for_delta_generation_by_product ( product_id ) do
619- DeploymentGroup
620- |> where ( [ dep ] , dep . product_id == ^ product_id )
621- |> join ( :inner , [ dep ] , dev in Device , on: dev . deployment_id == dep . id )
622- |> join ( :inner , [ dep , dev ] , f in Firmware , on: f . uuid == fragment ( "d1.firmware_metadata->>'uuid'" ) )
623- # Exclude the current firmware, we don't need to generate that one
624- |> where ( [ dep , dev , f ] , f . id != dep . firmware_id )
625- |> select ( [ dep , dev , f ] , { f . id , dep . firmware_id } )
626- |> Repo . all ( )
627- end
628-
629616 @ spec get_device_firmware_for_delta_generation_by_deployment_group ( binary ( ) ) ::
630617 list ( { source_firmware_id ( ) , target_firmware_id ( ) } )
631618 def get_device_firmware_for_delta_generation_by_deployment_group ( deployment_id ) do
@@ -636,6 +623,7 @@ defmodule NervesHub.Devices do
636623 # Exclude the current firmware, we don't need to generate that one
637624 |> where ( [ dep , dev , f ] , f . id != dep . firmware_id )
638625 |> select ( [ dep , dev , f ] , { f . id , dep . firmware_id } )
626+ |> distinct ( true )
639627 |> Repo . all ( )
640628 end
641629
@@ -777,24 +765,35 @@ defmodule NervesHub.Devices do
777765 defp do_resolve_update ( device , deployment_group , opts ) do
778766 case verify_update_eligibility ( device , deployment_group ) do
779767 { :ok , _device } ->
780- { :ok , url } = get_delta_or_firmware_url ( device , deployment_group )
781-
782- { :ok , meta } = Firmwares . metadata_from_firmware ( deployment_group . firmware )
783-
784- firmware_url =
785- if opts [ :firmware_proxy_url ] do
786- opts [ :firmware_proxy_url ] <> "?firmware=#{ Base . url_encode64 ( url , padding: false ) } "
787- else
788- url
789- end
768+ case get_delta_or_firmware_url ( device , deployment_group ) do
769+ { :ok , url } ->
770+ { :ok , meta } = Firmwares . metadata_from_firmware ( deployment_group . firmware )
771+
772+ firmware_url =
773+ if opts [ :firmware_proxy_url ] do
774+ opts [ :firmware_proxy_url ] <> "?firmware=#{ Base . url_encode64 ( url , padding: false ) } "
775+ else
776+ url
777+ end
778+
779+ % UpdatePayload {
780+ update_available: true ,
781+ firmware_url: firmware_url ,
782+ firmware_meta: meta ,
783+ deployment_group: deployment_group ,
784+ deployment_id: deployment_group . id
785+ }
786+
787+ { :error , reason } ->
788+ Logger . info (
789+ "Firmware URL could not be generated" ,
790+ reason: reason ,
791+ source_firmware: Map . get ( device . firmware_metadata , :uuid ) ,
792+ target_firmware: deployment_group . firmware . uuid
793+ )
790794
791- % UpdatePayload {
792- update_available: true ,
793- firmware_url: firmware_url ,
794- firmware_meta: meta ,
795- deployment_group: deployment_group ,
796- deployment_id: deployment_group . id
797- }
795+ % UpdatePayload { update_available: false }
796+ end
798797
799798 { :error , :deployment_group_not_active , _device } ->
800799 % UpdatePayload { update_available: false }
@@ -836,6 +835,23 @@ defmodule NervesHub.Devices do
836835 :delta == update_tool ( ) . device_update_type ( device , firmware )
837836 end
838837
838+ @ spec delta_ready? ( Device . t ( ) , Firmware . t ( ) ) :: boolean ( )
839+ def delta_ready? ( % Device { firmware_metadata: % { uuid: source_uuid } } , % Firmware { id: target_id , product_id: product_id } ) do
840+ source_firmware_id_query =
841+ Firmware
842+ |> where ( uuid: ^ source_uuid )
843+ |> where ( product_id: ^ product_id )
844+ |> select ( [ f ] , f . id )
845+
846+ query =
847+ FirmwareDelta
848+ |> where ( [ fd ] , fd . source_id == subquery ( source_firmware_id_query ) )
849+ |> where ( [ fd ] , fd . target_id == ^ target_id )
850+ |> where ( [ fd ] , fd . status == :completed )
851+
852+ Repo . exists? ( query )
853+ end
854+
839855 @ doc """
840856 Returns true if Version.match? and all deployment tags are in device tags.
841857 """
@@ -862,6 +878,7 @@ defmodule NervesHub.Devices do
862878
863879 DeviceEvents . deployment_assigned ( device )
864880
881+ deployment_group = Repo . preload ( deployment_group , :firmware )
865882 Map . put ( device , :deployment_group , deployment_group )
866883 end
867884
@@ -1722,116 +1739,74 @@ defmodule NervesHub.Devices do
17221739 @ doc """
17231740 Get firmware or delta update URL.
17241741 """
1725- @ spec get_delta_or_firmware_url ( Device . t ( ) , Firmware . t ( ) | DeploymentGroup . t ( ) ) ::
1726- { :ok , String . t ( ) } | { :error , :failure }
1727- def get_delta_or_firmware_url ( % Device { } = device , % DeploymentGroup { delta_updatable: true , firmware: target } ) do
1728- get_delta_or_firmware_url ( device , target )
1729- end
1742+ @ spec get_delta_or_firmware_url ( Device . t ( ) , DeploymentGroup . t ( ) ) ::
1743+ { :ok , String . t ( ) }
1744+ | { :error , :delta_not_completed }
1745+ | { :error , :device_does_not_support_deltas }
1746+ | { :error , :delta_not_found }
1747+ def get_delta_or_firmware_url ( % Device { firmware_metadata: % { uuid: source_uuid } } = device , % DeploymentGroup {
1748+ delta_updatable: true ,
1749+ firmware: % Firmware { delta_updatable: true } = target_firmware
1750+ } ) do
1751+ case Firmwares . get_firmware_by_product_id_and_uuid ( device . product_id , source_uuid ) do
1752+ { :ok , source_firmware } ->
1753+ case get_delta_if_ready ( device , source_firmware , target_firmware ) do
1754+ { :ok , delta } ->
1755+ Firmwares . get_firmware_url ( delta )
1756+
1757+ { :device_delta_updatable , false } ->
1758+ { :error , :device_does_not_support_deltas }
1759+
1760+ { :delta , { :ok , % FirmwareDelta { } } } ->
1761+ { :error , :delta_not_completed }
1762+
1763+ { :delta , { :error , :not_found } } ->
1764+ { :error , :delta_not_found }
1765+ end
17301766
1731- def get_delta_or_firmware_url (
1732- % { firmware_metadata: % { uuid: source_uuid } } = device ,
1733- % Firmware { delta_updatable: true } = target
1734- ) do
1735- case get_delta_if_ready ( device , target ) do
1736- { :ok , delta } ->
1737- Logger . info (
1738- "Delivering firmware delta" ,
1739- device_id: device . id ,
1740- source_firmware: source_uuid ,
1741- target_firmware: target . uuid ,
1742- delta: delta . id
1743- )
1744-
1745- Firmwares . get_firmware_url ( delta )
1746-
1747- { :delta_updatable , false } ->
1748- Logger . info (
1749- "Delivering full firmware as delta updates are not enabled" ,
1750- device_id: device . id ,
1751- source_firmware: source_uuid ,
1752- target_firmware: target . uuid
1753- )
1754-
1755- Firmwares . get_firmware_url ( target )
1756-
1757- { :firmware , _ } ->
1758- Logger . warning (
1759- "Delivering full firmware as device firmware could not be resolved" ,
1760- device_id: device . id ,
1761- source_firmware: source_uuid ,
1762- target_firmware: target . uuid
1763- )
1764-
1765- Firmwares . get_firmware_url ( target )
1766-
1767- { :delta , { :ok , % { status: status } = delta } } ->
1768- Logger . info (
1769- "Delivering full firmware as delta had status #{ status } " ,
1770- device_id: device . id ,
1771- source_firmware: source_uuid ,
1772- target_firmware: target . uuid ,
1773- delta: delta . id
1774- )
1775-
1776- Firmwares . get_firmware_url ( target )
1777-
1778- { :delta , { :error , :not_found } } ->
1779- Logger . info (
1780- "Delivering full firmware as no delta can be found" ,
1781- device_id: device . id ,
1782- source_firmware: source_uuid ,
1783- target_firmware: target . uuid
1784- )
1785-
1786- Firmwares . get_firmware_url ( target )
1767+ { :error , :not_found } ->
1768+ Firmwares . get_firmware_url ( target_firmware )
17871769 end
17881770 end
17891771
1790- def get_delta_or_firmware_url ( % Device { firmware_metadata: fw_meta } = device , % DeploymentGroup { firmware: target } = dg ) do
1791- Logger . warning (
1792- "Delivering full firmware: deltas disabled for deployment group." ,
1793- device_id: device . id ,
1794- deployment_group_id: dg . id ,
1795- source_firmware: Map . get ( fw_meta , :uuid ) ,
1796- target_firmware: target . uuid
1797- )
1798-
1799- Firmwares . get_firmware_url ( target )
1800- end
1772+ def get_delta_or_firmware_url ( % Device { } , % DeploymentGroup { firmware: target } ) , do: Firmwares . get_firmware_url ( target )
18011773
1802- def get_delta_or_firmware_url ( % Device { firmware_metadata: fw_meta } = device , % Firmware { } = target ) do
1803- Logger . warning (
1804- "Delivering full firmware: deltas disabled for firmware." ,
1805- device_id: device . id ,
1806- source_firmware: Map . get ( fw_meta , :uuid ) ,
1807- target_firmware: target . uuid
1808- )
1809-
1810- Firmwares . get_firmware_url ( target )
1811- end
1812-
1813- @ spec get_delta_if_ready ( Device . t ( ) , Firmware . t ( ) ) ::
1774+ @ spec get_delta_if_ready ( Device . t ( ) , Firmware . t ( ) , Firmware . t ( ) ) ::
18141775 { :ok , FirmwareDelta . t ( ) }
1815- | { :delta_updatable , false }
1816- | { :firmware , { :error , :not_found } }
1817- | { :firmware , :no_device_firmware_metadata }
1776+ | { :device_delta_updatable , false }
18181777 | { :delta , { :ok , FirmwareDelta . t ( ) } }
18191778 | { :delta , { :error , :not_found } }
1820- def get_delta_if_ready (
1821- % Device { firmware_metadata: % { uuid: source_firmware_uuid } , product_id: product_id } = device ,
1822- target_firmware
1823- ) do
1824- with { :delta_updatable , true } <-
1825- { :delta_updatable , delta_updatable? ( device , target_firmware ) } ,
1826- { :firmware , { :ok , source_firmware } } <-
1827- { :firmware , Firmwares . get_firmware_by_product_id_and_uuid ( product_id , source_firmware_uuid ) } ,
1779+ defp get_delta_if_ready ( device , source_firmware , target_firmware ) do
1780+ with { :device_delta_updatable , true } <-
1781+ { :device_delta_updatable , delta_updatable? ( device , target_firmware ) } ,
18281782 { :delta , { :ok , % { status: :completed } = delta } } <-
1829- { :delta , Firmwares . get_firmware_delta_by_source_and_target ( source_firmware , target_firmware ) } do
1783+ { :delta ,
1784+ Firmwares . get_firmware_delta_by_source_and_target (
1785+ source_firmware . id ,
1786+ target_firmware . id
1787+ ) } do
18301788 { :ok , delta }
18311789 end
18321790 end
18331791
1834- def get_delta_if_ready ( _device , _target_firmware ) , do: { :firmware , :no_device_firmware_metadata }
1792+ @ spec get_delta_url ( Device . t ( ) , Firmware . t ( ) ) ::
1793+ { :ok , String . t ( ) }
1794+ | { :error , :failure }
1795+ def get_delta_url ( % Device { firmware_metadata: % { uuid: source_uuid } } , % Firmware { id: target_id , product_id: product_id } ) do
1796+ source_firmware_id_query =
1797+ Firmware
1798+ |> where ( uuid: ^ source_uuid )
1799+ |> where ( product_id: ^ product_id )
1800+ |> select ( [ f ] , f . id )
1801+
1802+ delta =
1803+ FirmwareDelta
1804+ |> where ( [ fd ] , fd . source_id == subquery ( source_firmware_id_query ) )
1805+ |> where ( [ fd ] , fd . target_id == ^ target_id )
1806+ |> Repo . one ( )
1807+
1808+ Firmwares . get_firmware_url ( delta )
1809+ end
18351810
18361811 @ spec soft_deleted_devices_exist_for_product? ( non_neg_integer ( ) ) :: boolean ( )
18371812 def soft_deleted_devices_exist_for_product? ( product_id ) do
0 commit comments